I'm trying to create a juptyer notebook that facilities copying and updating a "dev" Portal webmap to my "prod" Portal (I'm working with two internal Portals, same layers published to each).
It's easy to copy a web map from one portal to the other, using the copy_item function from clone portal users groups and content | ArcGIS for Developers . However, I'm having problems updating the web map once I've copied it from dev to production.
As far as I can tell, all I'd need to do is change the urls (from my development ArcGIS server to my production ArcGIS server) in the json representation of the Portal item. It also seems like I should change the itemId for the layers as well, (I might just have to hardcode the production itemIds unless I want to search for the layers by name and retrieve the ids that way - I have yet to solve the best way to approach that problem).
Lastly, once I've modified the data dictionary / json representation from the web map, I just run the update method.
See the code below:
#####from some of the API documentation examples
TEXT_BASED_ITEM_TYPES = frozenset(['Web Map', 'Feature Service', 'Map Service','Web Scene',
'Image Service', 'Feature Collection',
'Feature Collection Template',
'Web Mapping Application', 'Mobile Application',
'Symbol Set', 'Color Set',
'Windows Viewer Configuration'])
ITEM_COPY_PROPERTIES = ['title', 'type', 'typeKeywords', 'description', 'tags',
'snippet', 'extent', 'spatialReference', 'name',
'accessInformation', 'licenseInfo', 'culture', 'url', ]
def copy_item(target, owner, folder, item):
with tempfile.TemporaryDirectory() as temp_dir:
copy_item = {}
for property_name in ITEM_COPY_PROPERTIES:
copy_item[property_name] = item[property_name]
data_file = None
if item.type in TEXT_BASED_ITEM_TYPES:
# If its a text-based item, then read the text and add it to the request.
if item.size > 0:
text = item.get_data(False)
#textstr = text.decode('utf-8')
copy_item['text'] = text
elif item.size > 0: # download data for all other types, not just item.type in FILE_BASED_ITEM_TYPES:
# download data and add to the request as a file
data_file = item.download(temp_dir)
thumbnail_file = item.download_thumbnail(temp_dir)
metadata_file = item.download_metadata(temp_dir)
# Add the item to the target portal
copied_item = target.content.add(copy_item, data_file, thumbnail_file,
metadata_file, owner, folder)
return copied_item
#####################################
##My Notebook
from arcgis.gis import GIS
from arcgis.gis import Item
from arcgis.gis import User
import tempfile
from IPython.display import display
source = GIS("dev portal", "username","password", verify_cert=False)
target = GIS("prod portal","username","password", verify_cert=False)
myDevMap = Item(source,"d8c2a39f366843e0a5e24c5299aeb57c")
copy_item(target,"user","folder",myDevMap)
######Once I've copied once, I just hardcode the item ID
myProdMap = Item(target,"cc6a02d3e9644cd08cc105ae30a06d87")
#here I'm retrieveing the json representation of the map
data = myProdMap.get_data(try_json=True)
replaceData = data
##this is where I replace the URLS "gis-dev" is the development url, and "gis" is the production
layers = data['operationalLayers']
for index in range(len(layers)):
if 'url' in layers[index].keys():
url = layers[index]['url']
if "gis-dev" in url:
newurl = url.replace("gis-dev","gis")
replaceData['operationalLayers'][index]['url']=newurl
myProdMap.update(data = replaceData)
When I try to run the update method, I get a whole host of errors, and I can't make heads or tails of them. So, am I doing something wrong / is there something I'm missing? I see some http vs https errors in here, along with some key errors as well. Don't really know what's going on but would love some assistance on this one.
AttributeError Traceback (most recent call last)
<ipython-input-27-5fe3a5afb862> in <module>()
----> 1 EONHome_fromDev.update(data = replaceData)
C:\Program Files\ArcGIS\Pro\bin\Python\envs\arcgispro-py3\lib\site-packages\arcgis\gis.py in update(self, item_properties, data, thumbnail, metadata)
2846 item_properties['tags'] = ",".join(item_properties['tags'])
2847
-> 2848 ret = self._portal.update_item(self.itemid, item_properties, data, thumbnail, metadata, self.owner, folder)
2849 if ret:
2850 self._hydrate()
C:\Program Files\ArcGIS\Pro\bin\Python\envs\arcgispro-py3\lib\site-packages\arcgis\_impl\portalpy.py in update_item(self, itemid, item_properties, data, thumbnail, metadata, owner, folder)
2014 files = []
2015 if data:
-> 2016 if _is_http_url(data):
2017 data = request.urlretrieve(data)[0]
2018 files.append(('file', data, os.path.basename(data)))
C:\Program Files\ArcGIS\Pro\bin\Python\envs\arcgispro-py3\lib\site-packages\arcgis\_impl\connection.py in _is_http_url(url)
1084 def _is_http_url(url):
1085 if url:
-> 1086 return urlparse(url).scheme in ['http', 'https']
1087
1088 def _unpack(obj_or_seq, key=None, flatten=False):
C:\Program Files\ArcGIS\Pro\bin\Python\envs\arcgispro-py3\lib\urllib\parse.py in urlparse(url, scheme, allow_fragments)
290 Note that we don't break the components up in smaller bits
291 (e.g. netloc is a single string) and we don't expand % escapes."""
--> 292 url, scheme, _coerce_result = _coerce_args(url, scheme)
293 splitresult = urlsplit(url, scheme, allow_fragments)
294 scheme, netloc, url, query, fragment = splitresult
C:\Program Files\ArcGIS\Pro\bin\Python\envs\arcgispro-py3\lib\urllib\parse.py in _coerce_args(*args)
110 if str_input:
111 return args + (_noop,)
--> 112 return _decode_args(args) + (_encode_result,)
113
114 # Result objects are more helpful than simple tuples
C:\Program Files\ArcGIS\Pro\bin\Python\envs\arcgispro-py3\lib\urllib\parse.py in _decode_args(args, encoding, errors)
94 def _decode_args(args, encoding=_implicit_encoding,
95 errors=_implicit_errors):
---> 96 return tuple(x.decode(encoding, errors) if x else '' for x in args)
97
98 def _coerce_args(*args):
C:\Program Files\ArcGIS\Pro\bin\Python\envs\arcgispro-py3\lib\urllib\parse.py in <genexpr>(.0)
94 def _decode_args(args, encoding=_implicit_encoding,
95 errors=_implicit_errors):
---> 96 return tuple(x.decode(encoding, errors) if x else '' for x in args)
97
98 def _coerce_args(*args):
AttributeError: 'dict' object has no attribute 'decode'
Please refer to the sample notebook - using and updating GIS content | ArcGIS for Developers that shows how you can update a web map.
Hope this helps,
Rohit
crackernutter Did you resolve this? The way I update items is create a webmap object from the portal item > call 'operationalLayers' on the webmap object > define the new url variable (hardcoded url) > update the web map layer dictionary > call update
Since you've been able to copy items using this API, maybe you could help me out on my question. Have been getting permissions errors when trying to copy webmaps. See link below...