ciocore 7.0.2b5__py2.py3-none-any.whl → 8.0.0__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ciocore might be problematic. Click here for more details.

Files changed (111) hide show
  1. ciocore/VERSION +1 -1
  2. ciocore/__init__.py +23 -1
  3. ciocore/api_client.py +422 -156
  4. ciocore/cli.py +503 -0
  5. ciocore/common.py +10 -1
  6. ciocore/config.py +86 -53
  7. ciocore/data.py +20 -73
  8. ciocore/docsite/404.html +723 -0
  9. ciocore/docsite/apidoc/api_client/index.html +3203 -0
  10. ciocore/docsite/apidoc/apidoc/index.html +868 -0
  11. ciocore/docsite/apidoc/config/index.html +1591 -0
  12. ciocore/docsite/apidoc/data/index.html +1480 -0
  13. ciocore/docsite/apidoc/hardware_set/index.html +2367 -0
  14. ciocore/docsite/apidoc/package_environment/index.html +1450 -0
  15. ciocore/docsite/apidoc/package_tree/index.html +2310 -0
  16. ciocore/docsite/assets/_mkdocstrings.css +16 -0
  17. ciocore/docsite/assets/images/favicon.png +0 -0
  18. ciocore/docsite/assets/javascripts/bundle.4e31edb1.min.js +29 -0
  19. ciocore/docsite/assets/javascripts/bundle.4e31edb1.min.js.map +8 -0
  20. ciocore/docsite/assets/javascripts/lunr/min/lunr.ar.min.js +1 -0
  21. ciocore/docsite/assets/javascripts/lunr/min/lunr.da.min.js +18 -0
  22. ciocore/docsite/assets/javascripts/lunr/min/lunr.de.min.js +18 -0
  23. ciocore/docsite/assets/javascripts/lunr/min/lunr.du.min.js +18 -0
  24. ciocore/docsite/assets/javascripts/lunr/min/lunr.es.min.js +18 -0
  25. ciocore/docsite/assets/javascripts/lunr/min/lunr.fi.min.js +18 -0
  26. ciocore/docsite/assets/javascripts/lunr/min/lunr.fr.min.js +18 -0
  27. ciocore/docsite/assets/javascripts/lunr/min/lunr.hi.min.js +1 -0
  28. ciocore/docsite/assets/javascripts/lunr/min/lunr.hu.min.js +18 -0
  29. ciocore/docsite/assets/javascripts/lunr/min/lunr.hy.min.js +1 -0
  30. ciocore/docsite/assets/javascripts/lunr/min/lunr.it.min.js +18 -0
  31. ciocore/docsite/assets/javascripts/lunr/min/lunr.ja.min.js +1 -0
  32. ciocore/docsite/assets/javascripts/lunr/min/lunr.jp.min.js +1 -0
  33. ciocore/docsite/assets/javascripts/lunr/min/lunr.kn.min.js +1 -0
  34. ciocore/docsite/assets/javascripts/lunr/min/lunr.ko.min.js +1 -0
  35. ciocore/docsite/assets/javascripts/lunr/min/lunr.multi.min.js +1 -0
  36. ciocore/docsite/assets/javascripts/lunr/min/lunr.nl.min.js +18 -0
  37. ciocore/docsite/assets/javascripts/lunr/min/lunr.no.min.js +18 -0
  38. ciocore/docsite/assets/javascripts/lunr/min/lunr.pt.min.js +18 -0
  39. ciocore/docsite/assets/javascripts/lunr/min/lunr.ro.min.js +18 -0
  40. ciocore/docsite/assets/javascripts/lunr/min/lunr.ru.min.js +18 -0
  41. ciocore/docsite/assets/javascripts/lunr/min/lunr.sa.min.js +1 -0
  42. ciocore/docsite/assets/javascripts/lunr/min/lunr.stemmer.support.min.js +1 -0
  43. ciocore/docsite/assets/javascripts/lunr/min/lunr.sv.min.js +18 -0
  44. ciocore/docsite/assets/javascripts/lunr/min/lunr.ta.min.js +1 -0
  45. ciocore/docsite/assets/javascripts/lunr/min/lunr.te.min.js +1 -0
  46. ciocore/docsite/assets/javascripts/lunr/min/lunr.th.min.js +1 -0
  47. ciocore/docsite/assets/javascripts/lunr/min/lunr.tr.min.js +18 -0
  48. ciocore/docsite/assets/javascripts/lunr/min/lunr.vi.min.js +1 -0
  49. ciocore/docsite/assets/javascripts/lunr/min/lunr.zh.min.js +1 -0
  50. ciocore/docsite/assets/javascripts/lunr/tinyseg.js +206 -0
  51. ciocore/docsite/assets/javascripts/lunr/wordcut.js +6708 -0
  52. ciocore/docsite/assets/javascripts/workers/search.dfff1995.min.js +42 -0
  53. ciocore/docsite/assets/javascripts/workers/search.dfff1995.min.js.map +8 -0
  54. ciocore/docsite/assets/stylesheets/main.83068744.min.css +1 -0
  55. ciocore/docsite/assets/stylesheets/main.83068744.min.css.map +1 -0
  56. ciocore/docsite/assets/stylesheets/palette.ecc896b0.min.css +1 -0
  57. ciocore/docsite/assets/stylesheets/palette.ecc896b0.min.css.map +1 -0
  58. ciocore/docsite/cmdline/docs/index.html +834 -0
  59. ciocore/docsite/cmdline/downloader/index.html +897 -0
  60. ciocore/docsite/cmdline/packages/index.html +841 -0
  61. ciocore/docsite/cmdline/uploader/index.html +950 -0
  62. ciocore/docsite/how-to-guides/index.html +831 -0
  63. ciocore/docsite/index.html +853 -0
  64. ciocore/docsite/logo.png +0 -0
  65. ciocore/docsite/objects.inv +0 -0
  66. ciocore/docsite/search/search_index.json +1 -0
  67. ciocore/docsite/sitemap.xml +3 -0
  68. ciocore/docsite/sitemap.xml.gz +0 -0
  69. ciocore/docsite/stylesheets/extra.css +26 -0
  70. ciocore/docsite/stylesheets/tables.css +167 -0
  71. ciocore/downloader/__init__.py +0 -0
  72. ciocore/downloader/base_downloader.py +644 -0
  73. ciocore/downloader/download_runner_base.py +47 -0
  74. ciocore/downloader/job_downloader.py +119 -0
  75. ciocore/{downloader.py → downloader/legacy_downloader.py} +0 -1
  76. ciocore/downloader/log.py +73 -0
  77. ciocore/downloader/logging_download_runner.py +87 -0
  78. ciocore/downloader/perpetual_downloader.py +63 -0
  79. ciocore/downloader/registry.py +97 -0
  80. ciocore/downloader/reporter.py +135 -0
  81. ciocore/file_utils.py +3 -3
  82. ciocore/hardware_set.py +0 -4
  83. ciocore/package_environment.py +67 -75
  84. ciocore/package_query.py +171 -0
  85. ciocore/package_tree.py +300 -377
  86. ciocore/retry.py +0 -0
  87. ciocore/uploader/_uploader.py +205 -152
  88. {ciocore-7.0.2b5.dist-info → ciocore-8.0.0.dist-info}/METADATA +34 -16
  89. ciocore-8.0.0.dist-info/RECORD +127 -0
  90. {ciocore-7.0.2b5.dist-info → ciocore-8.0.0.dist-info}/WHEEL +1 -1
  91. ciocore-8.0.0.dist-info/entry_points.txt +2 -0
  92. tests/extra_env_fixtures.py +57 -0
  93. tests/instance_type_fixtures.py +42 -8
  94. tests/project_fixtures.py +8 -0
  95. tests/test_api_client.py +121 -2
  96. tests/test_base_downloader.py +104 -0
  97. tests/test_cli.py +163 -0
  98. tests/test_common.py +8 -8
  99. tests/test_config.py +23 -9
  100. tests/test_data.py +144 -160
  101. tests/test_downloader.py +118 -0
  102. tests/test_hardware_set.py +69 -20
  103. tests/test_job_downloader.py +213 -0
  104. ciocore/__about__.py +0 -10
  105. ciocore/cli/__init__.py +0 -3
  106. ciocore/cli/conductor.py +0 -210
  107. ciocore-7.0.2b5.data/scripts/conductor +0 -19
  108. ciocore-7.0.2b5.data/scripts/conductor.bat +0 -13
  109. ciocore-7.0.2b5.dist-info/RECORD +0 -51
  110. tests/mocks/api_client_mock.py +0 -31
  111. {ciocore-7.0.2b5.dist-info → ciocore-8.0.0.dist-info}/top_level.txt +0 -0
ciocore/cli.py ADDED
@@ -0,0 +1,503 @@
1
+ import os
2
+ import logging
3
+ import click
4
+ import webbrowser
5
+ import http.server
6
+ import socketserver
7
+
8
+ from ciocore import loggeria, config, api_client, package_query
9
+
10
+ from ciocore import version as VERSION
11
+
12
+ from ciocore.uploader import Uploader
13
+ from ciocore.downloader.legacy_downloader import Downloader
14
+ from ciocore.downloader.logging_download_runner import LoggingDownloadRunner
15
+ from ciocore.downloader.log import LOGGER_NAME, LEVEL_MAP
16
+
17
+
18
+ LOG_LEVEL_HELP = """The logging level to display"""
19
+
20
+ LOG_DIR_HELP = """
21
+ Write a log file to the given directory. The log rotates, creating a new log file every day, while
22
+ storing logs for the last 7 days.
23
+ """
24
+ LOG_TO_CONSOLE_HELP = """
25
+ If set, logging will be output to the console as well as the logging file."""
26
+
27
+ THREADS_HELP = """The number of threads that should download simultaneously"""
28
+
29
+ UPLOADER_DATABASE_FILEPATH_HELP = (
30
+ "Specify a filepath to the local md5 caching database."
31
+ )
32
+ LOCATION_HELP = """
33
+ Specify a location tag to associate with uploads, downloads, and submissions. A location tag allows
34
+ you to limit the scope of your uploads and downloads to jobs sharing the same location tag. This is
35
+ useful while using the uploader or downloader in daemon mode.
36
+ """
37
+ UPLOADER_MD5_CACHING_HELP = """
38
+ Use cached md5s. This can dramatically improve the uploading times, as md5 checking can be very
39
+ time consuming. Caching md5s allows subsequent uploads (of the same files) to skip the md5
40
+ generation process (if the files appear to not have been modified since the last time they were
41
+ submitted). The cache is stored locally and uses a file's modification time and file size to
42
+ intelligently guess whether the file has changed. Set this flag to False if there is concern that
43
+ files may not be getting re-uploaded properly
44
+ """
45
+
46
+ UPLOADER_PATHS_HELP = """
47
+ A list of paths to upload. Use quotes if paths contain spaces or special characters"""
48
+
49
+ DOWNLOADER_JOB_ID_HELP = """
50
+ The job id(s) to download. When specified will only download those jobs and terminate afterwards
51
+ """
52
+
53
+ DOWNLOADER_OUTPUT_PATH_HELP = """
54
+ Override the output directory"""
55
+
56
+ PACKAGES_FORMAT_OPTIONS = ["text", "markdown", "html"]
57
+ PACKAGES_FORMAT_HELP = """
58
+ text: The output is a simple list of software names and versions, with nesting to indicate plugin
59
+ compatibility. Output is sent to stdout.
60
+
61
+ markdown: Designed for use in other markdown documentation systems where it benefits from consistent
62
+ styling. Output is sent to stdout and can be piped to a file.
63
+
64
+ html: Opens a browser window and displays the output in a simple html page.
65
+ """
66
+
67
+ DOCS_PORT_HELP = """
68
+ The port to serve the documentation on. Defaults to 8025.
69
+ """
70
+
71
+ DOWNLOADER_PAGE_SIZE_HELP = """
72
+ The number of files to request from the Conductor API at a time. Defaults to 50.
73
+ """
74
+
75
+ PROGRESS_INTERVAL_HELP = """
76
+ The number of milliseconds to pass before printing a emitting a progress message. Defaults to 500.
77
+ """
78
+ DEFAULT_PROGRESS_INTERVAL = 500
79
+
80
+ DOWNLOADER_FORCE_DOWNLOAD_HELP = """
81
+ Force download of files even if they already locally. MD5s will not be calculated or checked for this mode. The default is False.
82
+ """
83
+
84
+ DOWNLOAD_REGEX_HELP = """
85
+ A regular expression to filter the files to download. Only files whose names match the regex are downloaded. If a task has multiple files and the regex matches only a subset of them, that subset is considered to be the entire task. This means that by default, tasks are reported to the server as downloaded, even though they weren't all downloaded.
86
+ """
87
+
88
+ DOWNLOAD_DISABLE_REPORTING_HELP = """
89
+ Decide whether to report back to the server with the status of the download. If you use this flag the state of tasks on the server remains unaffected, whether it is downloaded or pernding.
90
+ """
91
+
92
+ SEQ_FORMAT_HELP = """
93
+ The format of the graph to display. The default is text.
94
+ """
95
+
96
+
97
+ DEFAULT_DOCS_PORT = 8025
98
+
99
+ LOG_FORMATTER = logging.Formatter(
100
+ "%(asctime)s %(name)s%(levelname)9s %(threadName)s: %(message)s"
101
+ )
102
+
103
+ logger = logging.getLogger("conductor.cli")
104
+
105
+
106
+ cfg = config.get()
107
+ DEFAULT_CONFIG_MD5_CACHING = cfg["md5_caching"]
108
+ DEFAULT_CONFIG_THREAD_COUNT = cfg["thread_count"]
109
+ DEFAULT_CONFIG_LOG_LEVEL = cfg["log_level"]
110
+ DEFAULT_DOWNLOADER_PAGE_SIZE = cfg["downloader_page_size"]
111
+
112
+
113
+ def _set_logging(log_level, log_to_console=True, log_dir=None, log_filename=None):
114
+ level = loggeria.LEVEL_MAP.get(log_level)
115
+ loggeria.setup_conductor_logging(
116
+ logger_level=level,
117
+ log_dirpath=log_dir,
118
+ log_filename=log_filename,
119
+ console_formatter=loggeria.FORMATTER_VERBOSE,
120
+ disable_console_logging= not log_to_console,
121
+ use_system_log=False,
122
+ )
123
+
124
+ def _register(client):
125
+ api_client.ApiClient.register_client(
126
+ client_name=client.CLIENT_NAME, client_version=VERSION
127
+ )
128
+
129
+ ########################### MAIN #################################
130
+ @click.group(invoke_without_command=True)
131
+ @click.pass_context
132
+ @click.option("-v", "--version", is_flag=True, help="Print the version and exit.")
133
+ def main(ctx, version):
134
+ """
135
+ Conductor Command-line interface.
136
+
137
+ To get help on subcommands, use the --help flag after the subcommand.
138
+
139
+ Example:
140
+ conductor download --help
141
+
142
+ """
143
+ if not ctx.invoked_subcommand:
144
+ if version:
145
+ click.echo(VERSION)
146
+ ctx.exit()
147
+ click.echo(ctx.get_help())
148
+ ctx.exit()
149
+
150
+ ############################# UPLOAD #############################
151
+ @main.command()
152
+ @click.option("-db", "--database_filepath", help=UPLOADER_DATABASE_FILEPATH_HELP)
153
+ @click.option(
154
+ "-md5",
155
+ "--md5_caching",
156
+ help=UPLOADER_MD5_CACHING_HELP,
157
+ type=bool,
158
+ default=DEFAULT_CONFIG_MD5_CACHING,
159
+ )
160
+ @click.option(
161
+ "-lv",
162
+ "--log_level",
163
+ help=LOG_LEVEL_HELP,
164
+ type=click.Choice(choices=loggeria.LEVELS, case_sensitive=False),
165
+ show_choices=True,
166
+ default=DEFAULT_CONFIG_LOG_LEVEL,
167
+ )
168
+ @click.option("-ld", "--log_dir", help=LOG_DIR_HELP)
169
+ @click.option("-lcl", "--log_to_console", is_flag=True, help=LOG_TO_CONSOLE_HELP, default=True)
170
+ @click.option(
171
+ "-tc",
172
+ "--thread_count",
173
+ type=int,
174
+ help=THREADS_HELP,
175
+ default=DEFAULT_CONFIG_THREAD_COUNT,
176
+ )
177
+ @click.option("-lc", "--location", help=LOCATION_HELP)
178
+ @click.argument("paths", nargs=-1, type=click.Path(exists=True, resolve_path=True))
179
+ def upload(
180
+ database_filepath, location, md5_caching, log_level, log_to_console, log_dir, thread_count, paths
181
+ ):
182
+ """Upload files to Conductor.
183
+
184
+ With no arguments, the uploader runs in daemon mode, watching for files to upload for submitted
185
+ jobs.
186
+
187
+ Alternatively, specify a list of paths to upload.
188
+
189
+ Example:
190
+ conductor upload file1 file2 file3
191
+ """
192
+ logfile = log_dir and os.path.join(log_dir, "conductor_ul.log")
193
+ _set_logging(log_level, log_to_console=log_to_console, log_dir=log_dir)
194
+
195
+ args_dict = {
196
+ "database_filepath": database_filepath,
197
+ "location": location,
198
+ "md5_caching": md5_caching,
199
+ "log_level": log_level,
200
+ "log_dir": log_dir,
201
+ "thread_count": thread_count,
202
+ }
203
+
204
+ up = Uploader(args_dict)
205
+
206
+ if paths:
207
+ up.assets_only(*paths)
208
+ return
209
+
210
+ up.main()
211
+
212
+
213
+ ########################### PACKAGES #############################
214
+ @main.command()
215
+ @click.option(
216
+ "-f",
217
+ "--fmt",
218
+ "--format",
219
+ default="text",
220
+ help=PACKAGES_FORMAT_HELP,
221
+ type=click.Choice(choices=PACKAGES_FORMAT_OPTIONS, case_sensitive=False),
222
+ )
223
+ def packages(fmt):
224
+ """List the software packages available on the render nodes in the cloud."""
225
+ package_query.pq(format=fmt)
226
+
227
+
228
+ ########################### DOCS #############################
229
+ @main.command()
230
+ @click.option(
231
+ "-p",
232
+ "--port",
233
+ help=DOCS_PORT_HELP,
234
+ type=int,
235
+ default=DEFAULT_DOCS_PORT,
236
+ )
237
+ def docs(port):
238
+ """Open the Conductor Core documentation in a web browser."""
239
+
240
+ handler = http.server.SimpleHTTPRequestHandler
241
+ socketserver.TCPServer.allow_reuse_address = True
242
+ with socketserver.TCPServer(("", port), handler) as httpd:
243
+ print(f"Server started at http://localhost:{port}")
244
+ print("Press Ctrl+C to stop the server")
245
+
246
+ # Change to the directory containing your site
247
+ current_dir = os.path.dirname(os.path.abspath(__file__))
248
+ site_dir = os.path.join(current_dir, "docsite")
249
+ os.chdir(site_dir)
250
+
251
+ # Start the server
252
+ localhost_url = f"http://localhost:{port}"
253
+ webbrowser.open(localhost_url)
254
+ httpd.serve_forever()
255
+
256
+
257
+ ########################### DEPRECATIONS #############################
258
+ ############################# UPLOADER #############################
259
+ DEPRECATED_PATHS_HELP = "Specify a list of paths to upload."
260
+
261
+
262
+ @main.command(deprecated=True)
263
+ @click.option("-db", "--database_filepath", help=UPLOADER_DATABASE_FILEPATH_HELP)
264
+ @click.option(
265
+ "-md5",
266
+ "--md5_caching",
267
+ help=UPLOADER_MD5_CACHING_HELP,
268
+ type=bool,
269
+ default=DEFAULT_CONFIG_MD5_CACHING,
270
+ )
271
+ @click.option(
272
+ "-lv",
273
+ "--log_level",
274
+ help=LOG_LEVEL_HELP,
275
+ type=click.Choice(choices=loggeria.LEVELS, case_sensitive=False),
276
+ show_choices=True,
277
+ default=DEFAULT_CONFIG_LOG_LEVEL,
278
+ )
279
+ @click.option("-ld", "--log_dir", help=LOG_DIR_HELP)
280
+ @click.option(
281
+ "-tc",
282
+ "--thread_count",
283
+ type=int,
284
+ help=THREADS_HELP,
285
+ default=DEFAULT_CONFIG_THREAD_COUNT,
286
+ )
287
+ @click.option("-lcl", "--log_to_console", is_flag=True, help=LOG_TO_CONSOLE_HELP, default=True)
288
+ @click.option("-lc", "--location", help=LOCATION_HELP)
289
+ @click.option(
290
+ "-p",
291
+ "--paths",
292
+ help=DEPRECATED_PATHS_HELP,
293
+ multiple=True,
294
+ type=click.Path(exists=True, resolve_path=True),
295
+ )
296
+ def uploader(
297
+ database_filepath, location, md5_caching, log_level, log_dir, log_to_console, thread_count, paths
298
+ ):
299
+ """Upload files to Conductor.
300
+
301
+ With no arguments, the uploader runs in daemon mode, watching for files to upload for submitted
302
+ jobs.
303
+
304
+ Alternatively, specify a list of paths to upload with the --paths option.
305
+
306
+ Example:
307
+ conductor upload file1 file2 file3
308
+ """
309
+ _set_logging(log_level, log_to_console=log_to_console, log_dir=log_dir)
310
+
311
+ args_dict = {
312
+ "database_filepath": database_filepath,
313
+ "location": location,
314
+ "md5_caching": md5_caching,
315
+ "log_level": log_level,
316
+ "log_dir": log_dir,
317
+ "thread_count": thread_count,
318
+ }
319
+
320
+ up = Uploader(args_dict)
321
+
322
+ if paths:
323
+ up.assets_only(*paths)
324
+ return
325
+
326
+ up.main()
327
+
328
+
329
+ ########################### DOWNLOADER #############################
330
+ DEPRECATED_JOBID_HELP = (
331
+ "Download all the files from completed tasks for the given jobs."
332
+ )
333
+ DEPRECATED_TASKID_HELP = "Download the files from the given tasks in the specified job."
334
+
335
+
336
+ @main.command(deprecated=True)
337
+ @click.option("-o", "--output", help=DOWNLOADER_OUTPUT_PATH_HELP)
338
+ @click.option("-j", "--job_id", help=DEPRECATED_JOBID_HELP)
339
+ @click.option("-t", "--task_id", help=DEPRECATED_TASKID_HELP)
340
+ @click.option(
341
+ "-lv",
342
+ "--log_level",
343
+ help=LOG_LEVEL_HELP,
344
+ type=click.Choice(choices=loggeria.LEVELS, case_sensitive=False),
345
+ show_choices=True,
346
+ default=DEFAULT_CONFIG_LOG_LEVEL,
347
+ )
348
+ @click.option("-ld", "--log_dir", help=LOG_DIR_HELP)
349
+ @click.option(
350
+ "-tc",
351
+ "--thread_count",
352
+ type=int,
353
+ help=THREADS_HELP,
354
+ default=DEFAULT_CONFIG_THREAD_COUNT,
355
+ )
356
+ @click.option("-lc", "--location", help=LOCATION_HELP)
357
+ @click.pass_context
358
+ def downloader(
359
+ ctx, job_id, task_id, output, location, log_level, log_dir, thread_count
360
+ ):
361
+ """
362
+ Download renders and other output files from Conductor. You can specify a job id and optional task id to
363
+ download, or you can omit all options and the downloader will run in daemon mode.
364
+
365
+ In daemon mode, the downloader polls for new jobs to download. You can specify a location tag to
366
+ limit the scope of the downloader to only download jobs that were submitted with the same
367
+ location tag.
368
+
369
+ Examples:
370
+ conductor downloader # daemon mode
371
+ conductor downloader --job_id --task_id 01234
372
+ conductor downloader --task_id --task_id 123
373
+ """
374
+ click.secho("This command has been deprecated. Please use conductor download instead.", fg='red')
375
+ logfile = log_dir and os.path.join(log_dir, "conductor_dl.log")
376
+ _set_logging(log_level, logfile)
377
+ _register(Downloader)
378
+
379
+ if not job_id and not task_id:
380
+ Downloader.start_daemon(
381
+ thread_count=thread_count, location=location, output_dir=output
382
+ )
383
+ ctx.exit(0)
384
+
385
+ Downloader.download_jobs(
386
+ (job_id,),
387
+ task_id=task_id,
388
+ thread_count=thread_count,
389
+ output_dir=output,
390
+ )
391
+
392
+
393
+ ########################### PAGED DOWNLOAD #############################
394
+ @main.command()
395
+ @click.option("-f", "--force", is_flag=True, help=DOWNLOADER_FORCE_DOWNLOAD_HELP)
396
+ @click.option(
397
+ "-ps",
398
+ "--page_size",
399
+ type=int,
400
+ help=DOWNLOADER_PAGE_SIZE_HELP,
401
+ default=DEFAULT_DOWNLOADER_PAGE_SIZE,
402
+ )
403
+ @click.option(
404
+ "-o", "--output-path",
405
+ type=click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True),
406
+ help=DOWNLOADER_OUTPUT_PATH_HELP,
407
+ )
408
+ @click.option(
409
+ "-pi",
410
+ "--progress_interval",
411
+ type=int,
412
+ help=PROGRESS_INTERVAL_HELP,
413
+ default=DEFAULT_PROGRESS_INTERVAL,
414
+ )
415
+ @click.option(
416
+ "-lv",
417
+ "--log_level",
418
+ help=LOG_LEVEL_HELP,
419
+ type=click.Choice(choices=loggeria.LEVELS, case_sensitive=False),
420
+ show_choices=True,
421
+ default=DEFAULT_CONFIG_LOG_LEVEL,
422
+ )
423
+ @click.option(
424
+ "-tc",
425
+ "--thread_count",
426
+ type=int,
427
+ help=THREADS_HELP,
428
+ default=DEFAULT_CONFIG_THREAD_COUNT,
429
+ )
430
+ @click.option(
431
+ "-dr",
432
+ "--disable-reporting",
433
+ help=DOWNLOAD_DISABLE_REPORTING_HELP,
434
+ is_flag=True,
435
+ default=False,
436
+ )
437
+ @click.option("-r", "--regex", help=DOWNLOAD_REGEX_HELP)
438
+ @click.option("-lc", "--location", help=LOCATION_HELP)
439
+ @click.argument("jobids", nargs=-1)
440
+ def download(
441
+ jobids,
442
+ page_size,
443
+ output_path,
444
+ location,
445
+ progress_interval,
446
+ log_level,
447
+ thread_count,
448
+ force,
449
+ regex,
450
+ disable_reporting,
451
+ ):
452
+
453
+ """
454
+ Download renders and other output files from Conductor. You can give a list of job ids to
455
+ download, or you can omit jobids and the downloader will run in daemon mode.
456
+
457
+ If you provide jobids, the default behavior is to download all the files from completed tasks
458
+ for those jobs. You can however specify an explicit set of tasks to downloade by providing a
459
+ task range spec after each job id. To do so, append a colon to the job id and then a compact
460
+ task specification. See the examples.
461
+
462
+ In daemon mode, the downloader polls for new jobs to download. You can specify a location tag to
463
+ limit the scope of the downloader to only download jobs that were submitted with the same
464
+ location tag.
465
+
466
+ Examples:
467
+
468
+ conductor download # daemon mode
469
+
470
+ conductor download 1234 1235
471
+
472
+ conductor download 1234:1-10
473
+
474
+ conductor download 1234:1-5x2,10,12-14
475
+
476
+ conductor download 1234:1-5 1235:5-10
477
+
478
+ """
479
+
480
+ _register(LoggingDownloadRunner)
481
+
482
+ # No longer uses Loggeria.
483
+ # Instead, it gets the logger with broken-pipe handling from the downloader.log module.
484
+ logging.getLogger(LOGGER_NAME).setLevel(LEVEL_MAP[log_level])
485
+
486
+ kwargs = {
487
+ "output_path": output_path,
488
+ "num_threads": thread_count,
489
+ "progress_interval": progress_interval,
490
+ "page_size": page_size,
491
+ "force": force,
492
+ "regex": regex,
493
+ "disable_reporting": disable_reporting,
494
+ }
495
+
496
+ dl = LoggingDownloadRunner(
497
+ jobids,
498
+ location,
499
+ **kwargs
500
+ )
501
+
502
+ dl.run()
503
+
ciocore/common.py CHANGED
@@ -364,7 +364,16 @@ def generate_md5(
364
364
 
365
365
  while len(file_buffer) > 0:
366
366
  hash_obj.update(file_buffer)
367
- file_buffer = file_obj.read(MD5_BLOCKSIZE)
367
+ try:
368
+ file_buffer = file_obj.read(MD5_BLOCKSIZE)
369
+ except OSError:
370
+ logger.log(
371
+ log_level,
372
+ "Cannot read file '%s'. Is it corrupted or unavailable?",
373
+ filepath,
374
+ )
375
+ raise
376
+
368
377
  curtime = time.time()
369
378
  bytes_processed = buffer_count * MD5_BLOCKSIZE
370
379
  percentage_processed = int((bytes_processed / float(file_size)) * 100)