Skip to content

Commit 3d79c0d

Browse files
authored
Merge pull request #1803 from xlt208/lingtaox
Updating update_items.py for updating sample notebooks online
2 parents 0028aaa + 49df8ee commit 3d79c0d

File tree

1 file changed

+90
-60
lines changed

1 file changed

+90
-60
lines changed

update_items.py

Lines changed: 90 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,21 @@
1212
1313
"""
1414

15-
import os
16-
import sys
1715
import argparse
18-
import traceback
1916
import json
20-
import re
2117
import logging
22-
log = logging.getLogger(__name__)
18+
import os
19+
import re
20+
import sys
21+
import traceback
2322

24-
import yaml
2523
import nbformat
26-
from nbconvert import HTMLExporter
24+
import requests
25+
import yaml
2726
from arcgis.gis import GIS
27+
from nbconvert import HTMLExporter
28+
29+
log = logging.getLogger(__name__)
2830

2931
ITEMS_METADATA_YAML_PATH = os.path.join(".", "items_metadata.yaml")
3032
THUMBNAILS_DIR = os.path.join(".", "static", "thumbnails")
@@ -35,21 +37,27 @@
3537
NB_PORTAL_TYPE_KEYWORDS = "Notebook, Python"
3638
NB_ITEM_PROPERTIES_RUNTIME_STAMP_ADVANCED = \
3739
{'notebookRuntimeName': 'ArcGIS Notebook Python 3 Advanced',
38-
'notebookRuntimeVersion': '5.0'}
40+
'notebookRuntimeVersion': ''}
3941
NB_ITEM_PROPERTIES_RUNTIME_STAMP_ADVANCED_GPU = \
40-
{'notebookRuntimeName': 'ArcGIS Notebook Python 3 Advanced with GPU support',
41-
'notebookRuntimeVersion': '5.0'}
42+
{'notebookRuntimeName': 'ArcGIS Notebook Python 3 Advanced with GPU support',
43+
'notebookRuntimeVersion': ''}
4244
NB_ITEM_PROPERTIES_RUNTIME_STAMP_STANDARD = \
4345
{'notebookRuntimeName': 'ArcGIS Notebook Python 3 Standard',
44-
'notebookRuntimeVersion': '5.0'}
46+
'notebookRuntimeVersion': ''}
4547
NB_ITEM_FOLDER = "Notebook Samples"
4648

49+
4750
def _main():
4851
"""Parses arguments, connects to GIS, reads YAML, uploads NBs"""
4952
args = _parse_cmd_line_args()
5053
_setup_logging(args)
5154
gis = GIS(args.portal_url, args.username,
5255
args.password, verify_cert=False)
56+
if args.version:
57+
NB_ITEM_PROPERTIES_RUNTIME_STAMP_ADVANCED["notebookRuntimeVersion"] = args.version
58+
NB_ITEM_PROPERTIES_RUNTIME_STAMP_STANDARD["notebookRuntimeVersion"] = args.version
59+
else:
60+
_get_current_runtime(gis)
5361
items_metadata_yaml = _read_items_metadata_yaml()
5462
if args.replace_profiles:
5563
_replace_profiles()
@@ -58,100 +66,120 @@ def _main():
5866
if s.failed_uploads:
5967
raise Exception(f"Some uploads failed: {s.failed_uploads}")
6068

69+
6170
def _parse_cmd_line_args():
6271
"""Parse CMD args, returns an object instance of all user passed in args"""
63-
parser = argparse.ArgumentParser(description = "Takes all notebooks "\
64-
"this in `gallery` directory, and will upload it to the specified "\
65-
"portal/org in the right group with the right categories. "\
66-
"(default is geosaurus.maps.arcgis.com, 'Esri Sample Notebooks' group)",
67-
formatter_class=argparse.RawTextHelpFormatter)
72+
parser = argparse.ArgumentParser(description="Takes all notebooks "
73+
"this in `gallery` directory, and will upload it to the specified "
74+
"portal/org in the right group with the right categories. "
75+
"(default is geosaurus.maps.arcgis.com, 'Esri Sample Notebooks' group)",
76+
formatter_class=argparse.RawTextHelpFormatter)
6877
parser.add_argument("--username", "-u", type=str,
69-
help="Required username for the portal/org")
78+
help="Required username for the portal/org")
7079
parser.add_argument("--password", "-p", type=str,
71-
help="Required password for the portal/org")
80+
help="Required password for the portal/org")
7281
parser.add_argument("--portal-url", "-r", type=str,
73-
help="The portal to connect to (Default:geosaurus.maps.arcgis.com)",
74-
default="https://geosaurus.maps.arcgis.com/")
82+
help="The portal to connect to (default: geosaurus.maps.arcgis.com)",
83+
default="https://geosaurus.maps.arcgis.com/")
84+
parser.add_argument("--version", "-ver", type=str,
85+
help="The version of notebook runtime to set on sample notebooks "
86+
"(default: the latest version)",
87+
default="")
7588
parser.add_argument("--verbose", "-v", action="store_true",
76-
help="Print all DEBUG log messages instead of just INFO")
89+
help="Print all DEBUG log messages instead of just INFO")
7790
parser.add_argument("--replace-profiles", "-c", action="store_true",
78-
help="Replace all profiles in notebooks with their appropriate username "\
79-
"and passwords. Does this by running misc/tools/replace_profiles.py")
80-
args = parser.parse_args(sys.argv[1:]) #don't use filename as 1st arg
91+
help="Replace all profiles in notebooks with their appropriate username "
92+
"and passwords. Does this by running misc/tools/replace_profiles.py")
93+
args = parser.parse_args(sys.argv[1:]) # don't use filename as 1st arg
8194
return args
8295

96+
8397
def _setup_logging(args):
8498
"""Sets up the logging based on args"""
8599
if args.verbose:
86100
log.setLevel(logging.DEBUG)
87101
else:
88-
log.setLevel(logging.INFO)
102+
log.setLevel(logging.INFO)
89103
stdout_handler = logging.StreamHandler(stream=sys.stdout)
90104
stdout_handler.setLevel(logging.DEBUG)
91105
stdout_handler.setFormatter(logging.Formatter(
92-
'----- %(levelname)s | '\
93-
'%(asctime)s | '\
94-
'%(filename)s line %(lineno)d'\
95-
' -----\n'\
106+
'----- %(levelname)s | '
107+
'%(asctime)s | '
108+
'%(filename)s line %(lineno)d'
109+
' -----\n'
96110
'"%(message)s"'))
97111
log.addHandler(stdout_handler)
98112
log.info("Logging at level {}.".format(logging.getLevelName(log.level)))
99113
log.debug("args passed in => {}".format(args))
100114

115+
116+
def _get_current_runtime(gis):
117+
ntbk_svr = gis.notebook_server[0]
118+
rest = ntbk_svr._url.replace("/admin", "/rest")
119+
rest_info = requests.get(f"{rest}/info?f=json", timeout=5, verify=False)
120+
version = rest_info.json()["currentRuntimeVersion"]
121+
NB_ITEM_PROPERTIES_RUNTIME_STAMP_ADVANCED["notebookRuntimeVersion"] = version
122+
NB_ITEM_PROPERTIES_RUNTIME_STAMP_STANDARD["notebookRuntimeVersion"] = version
123+
return version
124+
125+
101126
def _read_items_metadata_yaml():
102127
"""Returns the items_metadata.yaml file as a dict"""
103-
with open(ITEMS_METADATA_YAML_PATH) as f:
128+
with open(ITEMS_METADATA_YAML_PATH, encoding="utf-8") as f:
104129
return yaml.safe_load(f)
105130

131+
106132
def _replace_profiles():
107133
"""Runs misc/tools/replace_profiles.py to go through each notebook in the
108134
repo and replace profiles with usernames/passwords
109135
"""
110136
cmd = f"{sys.executable} {REPLACE_PROFILES_SCRIPT}"
111137
os.system(cmd)
112138

139+
113140
class ItemsUploader:
114141
def __init__(self, gis, items_metadata_yaml):
115142
self._gis = gis
116143
self._items_metadata_yaml = items_metadata_yaml
117144
self.failed_uploads = []
118145

119-
def upload_items(self, share_after_upload = True):
146+
def upload_items(self, share_after_upload=True):
120147
for entry in self._items_metadata_yaml["samples"] + \
121-
self._items_metadata_yaml["guides"] + \
122-
self._items_metadata_yaml["labs"]:
148+
self._items_metadata_yaml["guides"] + \
149+
self._items_metadata_yaml["labs"]:
123150
self._stage_and_upload_item(entry, share_after_upload)
124151

125-
def _stage_and_upload_item(self, entry, share_after_upload = True):
152+
def _stage_and_upload_item(self, entry, share_after_upload=True):
126153
log.info(f"Uploading {entry['title']}")
127154
log.debug(f" sample: {entry}")
128155
try:
129156
nb_path = entry["path"]
130157
self._preupload_check(entry['title'], nb_path)
131-
runtime_stamp = self._infer_runtime_stamp(entry.get("runtime", "standard"))
158+
runtime_stamp = self._infer_runtime_stamp(
159+
entry.get("runtime", "standard"))
132160
categories = entry.get("categories", None)
133161
self._stamp_file_with_runtime(nb_path, runtime_stamp)
134162
item_id = self._infer_item_id(entry["url"])
135163
item = self.update_item(
136-
item_id = item_id,
137-
item_type = NB_PORTAL_TYPE,
138-
item_type_keywords = NB_PORTAL_TYPE_KEYWORDS,
139-
title = entry['title'],
140-
categories = categories,
141-
snippet = entry['snippet'],
142-
description = entry['description'],
143-
license_info = entry['licenseInfo'],
144-
tags = entry['tags'],
145-
nb_path = nb_path,
146-
runtime_stamp = runtime_stamp,
147-
thumbnail = entry['thumbnail'])
164+
item_id=item_id,
165+
item_type=NB_PORTAL_TYPE,
166+
item_type_keywords=NB_PORTAL_TYPE_KEYWORDS,
167+
title=entry['title'],
168+
categories=categories,
169+
snippet=entry['snippet'],
170+
description=entry['description'],
171+
license_info=entry['licenseInfo'],
172+
tags=entry['tags'],
173+
nb_path=nb_path,
174+
runtime_stamp=runtime_stamp,
175+
thumbnail=entry['thumbnail'])
148176
if share_after_upload:
149-
item.share(everyone = True)
177+
item.sharing.sharing_level = "EVERYONE"
150178
item.protect()
151179
if categories:
152180
self._assign_categories_to_item(item, categories)
153181
self._apply_html_preview_to_item(item, nb_path)
154-
log.info(f" Uploaded succeded -> {item.homepage}")
182+
log.info(f" Uploaded succeeded -> {item.homepage}")
155183
except Exception as e:
156184
self.failed_uploads.append(entry['title'])
157185
log.warn(f" Couldn't upload {entry['title']}: {e}")
@@ -170,11 +198,11 @@ def update_item(self, item_id, item_type, item_type_keywords, title, categories,
170198
snippet, description, license_info, tags, nb_path,
171199
runtime_stamp, thumbnail):
172200
"""Actually uploads the notebook item to the portal"""
173-
item_properties = {"title" : title,
174-
"snippet" : snippet,
175-
"description" : description,
176-
"licenseInfo" : license_info,
177-
"tags" : tags,
201+
item_properties = {"title": title,
202+
"snippet": snippet,
203+
"description": description,
204+
"licenseInfo": license_info,
205+
"tags": tags,
178206
"properties": runtime_stamp}
179207
if categories:
180208
item_properties["categories"] = categories
@@ -188,11 +216,12 @@ def update_item(self, item_id, item_type, item_type_keywords, title, categories,
188216
log.debug(f'item {existing_item.homepage} exists, updating...')
189217
item_properties["url"] = existing_item.homepage
190218
existing_item.update(item_properties,
191-
data = nb_path,
192-
thumbnail = thumbnail)
219+
data=nb_path,
220+
thumbnail=thumbnail)
193221
resp = existing_item
194222
else:
195-
raise Exception(f"Could not find item {item_id} to update. Failing!")
223+
raise Exception(
224+
f"Could not find item {item_id} to update. Failing!")
196225
return resp
197226

198227
def _assign_categories_to_item(self, item, categories):
@@ -207,8 +236,8 @@ def _apply_html_preview_to_item(self, item, nb_path):
207236

208237
json_file_name = "notebook_preview.json"
209238
json_file_path = os.path.join(".", json_file_name)
210-
with open(json_file_path, 'w') as f:
211-
json.dump({"html" : html_str}, f)
239+
with open(json_file_path, 'w', encoding="utf-8") as f:
240+
json.dump({"html": html_str}, f)
212241

213242
if item.resources.list():
214243
item.resources.remove()
@@ -239,11 +268,12 @@ def _stamp_file_with_runtime(self, notebook_file_path, runtime_stamp):
239268
nb['metadata']['esriNotebookRuntime'] = runtime_stamp
240269
nbformat.write(nb, notebook_file_path, nbformat.NO_CONVERT)
241270

271+
242272
if __name__ == "__main__":
243273
try:
244274
_main()
245275
sys.exit(0)
246276
except Exception as e:
247277
log.exception(e)
248-
log.info("Program did not succesfully complete (unhandled exception)")
278+
log.info("Program did not successfully complete (unhandled exception)")
249279
sys.exit(1)

0 commit comments

Comments
 (0)