ciocore 5.1.1__py2.py3-none-any.whl → 10.0.0b3__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.
- ciocore/VERSION +1 -1
- ciocore/__init__.py +23 -1
- ciocore/api_client.py +655 -160
- ciocore/auth/__init__.py +5 -3
- ciocore/cli.py +501 -0
- ciocore/common.py +15 -13
- ciocore/conductor_submit.py +77 -60
- ciocore/config.py +127 -13
- ciocore/data.py +162 -77
- ciocore/docsite/404.html +746 -0
- ciocore/docsite/apidoc/api_client/index.html +3605 -0
- ciocore/docsite/apidoc/apidoc/index.html +909 -0
- ciocore/docsite/apidoc/config/index.html +1652 -0
- ciocore/docsite/apidoc/data/index.html +1553 -0
- ciocore/docsite/apidoc/hardware_set/index.html +2460 -0
- ciocore/docsite/apidoc/package_environment/index.html +1507 -0
- ciocore/docsite/apidoc/package_tree/index.html +2386 -0
- ciocore/docsite/assets/_mkdocstrings.css +16 -0
- ciocore/docsite/assets/images/favicon.png +0 -0
- ciocore/docsite/assets/javascripts/bundle.471ce7a9.min.js +29 -0
- ciocore/docsite/assets/javascripts/bundle.471ce7a9.min.js.map +7 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.ar.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.da.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.de.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.du.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.el.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.es.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.fi.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.fr.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.he.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.hi.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.hu.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.hy.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.it.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.ja.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.jp.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.kn.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.ko.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.multi.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.nl.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.no.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.pt.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.ro.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.ru.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.sa.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.stemmer.support.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.sv.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.ta.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.te.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.th.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.tr.min.js +18 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.vi.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/min/lunr.zh.min.js +1 -0
- ciocore/docsite/assets/javascripts/lunr/tinyseg.js +206 -0
- ciocore/docsite/assets/javascripts/lunr/wordcut.js +6708 -0
- ciocore/docsite/assets/javascripts/workers/search.b8dbb3d2.min.js +42 -0
- ciocore/docsite/assets/javascripts/workers/search.b8dbb3d2.min.js.map +7 -0
- ciocore/docsite/assets/stylesheets/main.3cba04c6.min.css +1 -0
- ciocore/docsite/assets/stylesheets/main.3cba04c6.min.css.map +1 -0
- ciocore/docsite/assets/stylesheets/palette.06af60db.min.css +1 -0
- ciocore/docsite/assets/stylesheets/palette.06af60db.min.css.map +1 -0
- ciocore/docsite/cmdline/docs/index.html +871 -0
- ciocore/docsite/cmdline/downloader/index.html +934 -0
- ciocore/docsite/cmdline/packages/index.html +878 -0
- ciocore/docsite/cmdline/uploader/index.html +995 -0
- ciocore/docsite/how-to-guides/index.html +869 -0
- ciocore/docsite/index.html +895 -0
- ciocore/docsite/logo.png +0 -0
- ciocore/docsite/objects.inv +0 -0
- ciocore/docsite/search/search_index.json +1 -0
- ciocore/docsite/sitemap.xml +3 -0
- ciocore/docsite/sitemap.xml.gz +0 -0
- ciocore/docsite/stylesheets/extra.css +26 -0
- ciocore/docsite/stylesheets/tables.css +167 -0
- ciocore/downloader/base_downloader.py +644 -0
- ciocore/downloader/download_runner_base.py +47 -0
- ciocore/downloader/job_downloader.py +119 -0
- ciocore/{downloader.py → downloader/legacy_downloader.py} +12 -9
- ciocore/downloader/log.py +73 -0
- ciocore/downloader/logging_download_runner.py +87 -0
- ciocore/downloader/perpetual_downloader.py +63 -0
- ciocore/downloader/registry.py +97 -0
- ciocore/downloader/reporter.py +135 -0
- ciocore/exceptions.py +8 -2
- ciocore/file_utils.py +51 -50
- ciocore/hardware_set.py +449 -0
- ciocore/loggeria.py +89 -20
- ciocore/package_environment.py +110 -48
- ciocore/package_query.py +182 -0
- ciocore/package_tree.py +319 -258
- ciocore/retry.py +0 -0
- ciocore/uploader/_uploader.py +547 -364
- ciocore/uploader/thread_queue_job.py +176 -0
- ciocore/uploader/upload_stats/__init__.py +3 -4
- ciocore/uploader/upload_stats/stats_formats.py +10 -4
- ciocore/validator.py +34 -2
- ciocore/worker.py +174 -151
- ciocore-10.0.0b3.dist-info/METADATA +928 -0
- ciocore-10.0.0b3.dist-info/RECORD +128 -0
- {ciocore-5.1.1.dist-info → ciocore-10.0.0b3.dist-info}/WHEEL +1 -1
- ciocore-10.0.0b3.dist-info/entry_points.txt +2 -0
- tests/instance_type_fixtures.py +175 -0
- tests/package_fixtures.py +205 -0
- tests/test_api_client.py +297 -12
- tests/test_base_downloader.py +104 -0
- tests/test_cli.py +149 -0
- tests/test_common.py +1 -7
- tests/test_config.py +40 -18
- tests/test_data.py +162 -173
- tests/test_downloader.py +118 -0
- tests/test_hardware_set.py +139 -0
- tests/test_job_downloader.py +213 -0
- tests/test_package_query.py +38 -0
- tests/test_package_tree.py +91 -291
- tests/test_submit.py +44 -18
- tests/test_uploader.py +1 -4
- ciocore/__about__.py +0 -10
- ciocore/cli/conductor.py +0 -191
- ciocore/compat.py +0 -15
- ciocore-5.1.1.data/scripts/conductor +0 -19
- ciocore-5.1.1.data/scripts/conductor.bat +0 -13
- ciocore-5.1.1.dist-info/METADATA +0 -408
- ciocore-5.1.1.dist-info/RECORD +0 -47
- tests/mocks/api_client_mock.py +0 -51
- /ciocore/{cli → downloader}/__init__.py +0 -0
- {ciocore-5.1.1.dist-info → ciocore-10.0.0b3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
import ciocore.exceptions
|
|
4
|
+
from ciocore import loggeria
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger(
|
|
8
|
+
"{}.uploader".format(loggeria.CONDUCTOR_LOGGER_NAME))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ThreadQueueJob():
|
|
12
|
+
"""
|
|
13
|
+
This class is a data structure that holds all the necessary information for
|
|
14
|
+
file upload jobs that are progressing through all the workers in the uploader
|
|
15
|
+
module.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, path, md5, project=None):
|
|
19
|
+
|
|
20
|
+
self.path = path
|
|
21
|
+
self.file_md5 = md5 # MD5 of the file as it currently exists on disk
|
|
22
|
+
|
|
23
|
+
self.file_size = None # In bytes
|
|
24
|
+
self.upload_type = None # Single part vs multi part
|
|
25
|
+
self.already_uploaded = False # Has this file already been uploaded to Conductor?
|
|
26
|
+
self.project = project # The Conductor Project that this job belongs to
|
|
27
|
+
|
|
28
|
+
self.file_upload_id = None # This is different than the ID for the Upload entity
|
|
29
|
+
self._parts = [] # If it's a multi-part upload, this holds the parts info
|
|
30
|
+
self.total_parts = None # The total number of parts for a multi-part upload
|
|
31
|
+
|
|
32
|
+
self.presigned_url = None # The presigned URL to upload to
|
|
33
|
+
self.part_index = None # If multi-part, this is the part number/index
|
|
34
|
+
self.kms_key_name = None # KMS Key name, if applicable
|
|
35
|
+
self.etag = None # ETag returned from upload, only for multi-part uploads
|
|
36
|
+
|
|
37
|
+
def set_parts(self, parts):
|
|
38
|
+
"""
|
|
39
|
+
Sets the parts information for a multi-part upload.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
parts (list): A list of parts information, each part is a dict with
|
|
43
|
+
'partNumber' and 'url' keys.
|
|
44
|
+
"""
|
|
45
|
+
self._parts = parts
|
|
46
|
+
self.total_parts = len(parts)
|
|
47
|
+
|
|
48
|
+
def get_parts(self):
|
|
49
|
+
"""
|
|
50
|
+
Returns a list of all the parts.
|
|
51
|
+
|
|
52
|
+
Return: A list of parts information, each part is a dict with
|
|
53
|
+
'partNumber' and 'url' keys.
|
|
54
|
+
|
|
55
|
+
"""
|
|
56
|
+
return self._parts
|
|
57
|
+
|
|
58
|
+
def create_multipart_jobs(self):
|
|
59
|
+
"""
|
|
60
|
+
Create a new ThreadQueueJob for each part of the multipart upload. All
|
|
61
|
+
the details that are common to all parts are copied into each new
|
|
62
|
+
ThreadQueueJob
|
|
63
|
+
|
|
64
|
+
Yields:
|
|
65
|
+
A new ThreadQueueJob
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
for part in self.get_parts():
|
|
69
|
+
|
|
70
|
+
part_job = ThreadQueueJob(path=self.path,
|
|
71
|
+
md5=self.file_md5)
|
|
72
|
+
|
|
73
|
+
part_job.file_size = self.file_size
|
|
74
|
+
part_job.upload_type = self.upload_type
|
|
75
|
+
part_job.file_upload_id = self.file_upload_id
|
|
76
|
+
part_job.alredy_uploaded = self.already_uploaded
|
|
77
|
+
|
|
78
|
+
part_job.part_size = self.part_size
|
|
79
|
+
part_job.total_parts = self.total_parts
|
|
80
|
+
part_job.kms_key_name = self.kms_key_name
|
|
81
|
+
|
|
82
|
+
part_job.presigned_url = part['url']
|
|
83
|
+
part_job.part_index = part['partNumber']
|
|
84
|
+
logger.debug("Created part for ({}) part number {} (etag: {})".format(self.path, part['partNumber'], part.get('etag', 'N/A')))
|
|
85
|
+
yield part_job
|
|
86
|
+
|
|
87
|
+
def is_multipart(self):
|
|
88
|
+
return self.upload_type == "multiPartURLs"
|
|
89
|
+
|
|
90
|
+
def is_vendor_aws(self):
|
|
91
|
+
|
|
92
|
+
if self.presigned_url is None:
|
|
93
|
+
raise ciocore.exceptions.UploadError(
|
|
94
|
+
"Presigned URL is None, cannot determine vendor."
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
return "amazonaws" in self.presigned_url
|
|
98
|
+
|
|
99
|
+
def is_vendor_cw(self):
|
|
100
|
+
|
|
101
|
+
if self.presigned_url is None:
|
|
102
|
+
raise ciocore.exceptions.UploadError(
|
|
103
|
+
"Presigned URL is None, cannot determine vendor."
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
return "coreweave" in self.presigned_url
|
|
107
|
+
|
|
108
|
+
def is_vendor_gcp(self):
|
|
109
|
+
|
|
110
|
+
if self.presigned_url is None:
|
|
111
|
+
raise ciocore.exceptions.UploadError(
|
|
112
|
+
"Presigned URL is None, cannot determine vendor."
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
return "gcp" in self.presigned_url
|
|
116
|
+
|
|
117
|
+
def __str__(self):
|
|
118
|
+
return "<STR: {} ({})>".format(self.path, self.file_md5)
|
|
119
|
+
|
|
120
|
+
def __repr__(self):
|
|
121
|
+
return "<REPR: {} ({})>".format(self.path, self.file_md5)
|
|
122
|
+
|
|
123
|
+
@staticmethod
|
|
124
|
+
def format_for_upload_request(jobs):
|
|
125
|
+
"""
|
|
126
|
+
Given a list of ThreadQueueJobs, create the expected json-compatible
|
|
127
|
+
structure expected by the AE endpoint to generate pre-signed URLs
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
jobs (list): A list of ThreadQueueJobs objects
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
A list of dicts (keys: path, hash, size) for each ThreadQueueJob
|
|
134
|
+
"""
|
|
135
|
+
|
|
136
|
+
request_data_struct = []
|
|
137
|
+
|
|
138
|
+
for job in jobs:
|
|
139
|
+
request_data_struct.append(
|
|
140
|
+
{
|
|
141
|
+
"path": job.path,
|
|
142
|
+
"hash": job.file_md5,
|
|
143
|
+
"size": job.file_size,
|
|
144
|
+
}
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
return request_data_struct
|
|
148
|
+
|
|
149
|
+
@staticmethod
|
|
150
|
+
def aggregate_parts(parts):
|
|
151
|
+
"""
|
|
152
|
+
Given a list of ThreadQueueJobs's (that represent the parts of a single
|
|
153
|
+
file) create the expected json-compatible structure expected by the AE
|
|
154
|
+
endpoint to generate pre-signed URLs
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
jobs (list): A list of ThreadQueueJobs objects
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
A list of dicts (keys: path, hash, size) for each ThreadQueueJob
|
|
161
|
+
|
|
162
|
+
Helper function to take all the parts of a multipart upload and put
|
|
163
|
+
them into a format that's expected for the HTTP call.
|
|
164
|
+
"""
|
|
165
|
+
|
|
166
|
+
completed_parts_payload = []
|
|
167
|
+
|
|
168
|
+
for part in parts:
|
|
169
|
+
completed_parts_payload.append({'partNumber': part.part_index,
|
|
170
|
+
'etag': part.etag}
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
# AWS requires part numbers to be in ascending order
|
|
174
|
+
completed_parts_payload.sort(key=lambda x: x['partNumber'])
|
|
175
|
+
|
|
176
|
+
return completed_parts_payload
|
|
@@ -8,7 +8,7 @@ class UploadStats(object):
|
|
|
8
8
|
'''
|
|
9
9
|
|
|
10
10
|
TEMPLATE = """
|
|
11
|
-
|
|
11
|
+
{title:#^80}
|
|
12
12
|
files to process: {self.files_to_analyze}
|
|
13
13
|
files to upload: {self.files_to_upload}
|
|
14
14
|
data to upload: {self.bytes_to_upload}
|
|
@@ -17,8 +17,7 @@ class UploadStats(object):
|
|
|
17
17
|
percent complete: {self.percent_complete}
|
|
18
18
|
transfer rate: {self.transfer_rate}/s
|
|
19
19
|
time remaining: {self.time_remaining}
|
|
20
|
-
|
|
21
|
-
################################################################################
|
|
20
|
+
{footer_char:^80}
|
|
22
21
|
"""
|
|
23
22
|
|
|
24
23
|
def __init__(self):
|
|
@@ -34,7 +33,7 @@ class UploadStats(object):
|
|
|
34
33
|
self.file_progress = {}
|
|
35
34
|
|
|
36
35
|
def get_formatted_text(self):
|
|
37
|
-
return self.TEMPLATE.format(self=self)
|
|
36
|
+
return self.TEMPLATE.format(self=self, title=' PROGRESS STATUS ', footer_char='#'*80)
|
|
38
37
|
|
|
39
38
|
@classmethod
|
|
40
39
|
def create(cls, metric_store, num_files_to_process, job_start_time):
|
|
@@ -42,11 +42,17 @@ class FileProgressValue(StatValue):
|
|
|
42
42
|
file_progress_text = []
|
|
43
43
|
|
|
44
44
|
for filename, progress_fields in self.value.items():
|
|
45
|
-
|
|
46
|
-
file_progress_text.append("{}: {} Bytes/{} Bytes".format(filename,
|
|
47
|
-
progress_fields['bytes_uploaded'],
|
|
48
|
-
progress_fields['bytes_to_upload']))
|
|
49
45
|
|
|
46
|
+
if progress_fields['already_uploaded']:
|
|
47
|
+
file_progress_text.append("{}{} (cached)".format(' '*24, filename))
|
|
48
|
+
|
|
49
|
+
else:
|
|
50
|
+
file_progress_text.append("{}{}: {} Bytes/{} Bytes".format(' '*24,
|
|
51
|
+
filename,
|
|
52
|
+
|
|
53
|
+
progress_fields['bytes_uploaded'],
|
|
54
|
+
progress_fields['bytes_to_upload']))
|
|
55
|
+
|
|
50
56
|
return "\n".join(file_progress_text)
|
|
51
57
|
|
|
52
58
|
class PercentageValue(StatValue):
|
ciocore/validator.py
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A system to facilitate pre-submission checks in submission tools.
|
|
3
|
+
|
|
4
|
+
Submitters can implement Validator plugins by inheriting from Validator, in order to check for
|
|
5
|
+
things like paths, suitable hardware, cameras, and so on.
|
|
6
|
+
|
|
7
|
+
Typically, a validation runner will be set up in each submitter's source code to discover and run
|
|
8
|
+
all Validator plugins.
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
|
|
1
12
|
import re
|
|
2
13
|
|
|
3
14
|
|
|
@@ -8,10 +19,31 @@ class ValidationError(Exception):
|
|
|
8
19
|
pass
|
|
9
20
|
|
|
10
21
|
class Validator(object):
|
|
11
|
-
|
|
12
|
-
DESCRIPTION = ""
|
|
13
22
|
|
|
14
23
|
def __init__(self, submitter):
|
|
24
|
+
"""
|
|
25
|
+
Base class, creates a Validator and initializes storage for errors, warnings, and info messages.
|
|
26
|
+
|
|
27
|
+
Arguments:
|
|
28
|
+
|
|
29
|
+
* **`submitter`** -- The submitter object, such as a ConductorRender node in Maya, or a
|
|
30
|
+
dialog in Cinema4D. This can be useful for checking submitter settings, but is not always
|
|
31
|
+
needed.
|
|
32
|
+
|
|
33
|
+
???+ example
|
|
34
|
+
``` python
|
|
35
|
+
|
|
36
|
+
from ciocore.validator import Validator
|
|
37
|
+
|
|
38
|
+
class ValidateCheckSomething(Validator):
|
|
39
|
+
def run(self, layername):
|
|
40
|
+
|
|
41
|
+
okay = get_some_value_from_the_scene()
|
|
42
|
+
if not okay:
|
|
43
|
+
self.add_warning("There was an issue with a value on layer {}.".format(layername))
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
"""
|
|
15
47
|
self._submitter = submitter
|
|
16
48
|
self.errors = set()
|
|
17
49
|
self.warnings = set()
|