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.
Files changed (126) hide show
  1. ciocore/VERSION +1 -1
  2. ciocore/__init__.py +23 -1
  3. ciocore/api_client.py +655 -160
  4. ciocore/auth/__init__.py +5 -3
  5. ciocore/cli.py +501 -0
  6. ciocore/common.py +15 -13
  7. ciocore/conductor_submit.py +77 -60
  8. ciocore/config.py +127 -13
  9. ciocore/data.py +162 -77
  10. ciocore/docsite/404.html +746 -0
  11. ciocore/docsite/apidoc/api_client/index.html +3605 -0
  12. ciocore/docsite/apidoc/apidoc/index.html +909 -0
  13. ciocore/docsite/apidoc/config/index.html +1652 -0
  14. ciocore/docsite/apidoc/data/index.html +1553 -0
  15. ciocore/docsite/apidoc/hardware_set/index.html +2460 -0
  16. ciocore/docsite/apidoc/package_environment/index.html +1507 -0
  17. ciocore/docsite/apidoc/package_tree/index.html +2386 -0
  18. ciocore/docsite/assets/_mkdocstrings.css +16 -0
  19. ciocore/docsite/assets/images/favicon.png +0 -0
  20. ciocore/docsite/assets/javascripts/bundle.471ce7a9.min.js +29 -0
  21. ciocore/docsite/assets/javascripts/bundle.471ce7a9.min.js.map +7 -0
  22. ciocore/docsite/assets/javascripts/lunr/min/lunr.ar.min.js +1 -0
  23. ciocore/docsite/assets/javascripts/lunr/min/lunr.da.min.js +18 -0
  24. ciocore/docsite/assets/javascripts/lunr/min/lunr.de.min.js +18 -0
  25. ciocore/docsite/assets/javascripts/lunr/min/lunr.du.min.js +18 -0
  26. ciocore/docsite/assets/javascripts/lunr/min/lunr.el.min.js +1 -0
  27. ciocore/docsite/assets/javascripts/lunr/min/lunr.es.min.js +18 -0
  28. ciocore/docsite/assets/javascripts/lunr/min/lunr.fi.min.js +18 -0
  29. ciocore/docsite/assets/javascripts/lunr/min/lunr.fr.min.js +18 -0
  30. ciocore/docsite/assets/javascripts/lunr/min/lunr.he.min.js +1 -0
  31. ciocore/docsite/assets/javascripts/lunr/min/lunr.hi.min.js +1 -0
  32. ciocore/docsite/assets/javascripts/lunr/min/lunr.hu.min.js +18 -0
  33. ciocore/docsite/assets/javascripts/lunr/min/lunr.hy.min.js +1 -0
  34. ciocore/docsite/assets/javascripts/lunr/min/lunr.it.min.js +18 -0
  35. ciocore/docsite/assets/javascripts/lunr/min/lunr.ja.min.js +1 -0
  36. ciocore/docsite/assets/javascripts/lunr/min/lunr.jp.min.js +1 -0
  37. ciocore/docsite/assets/javascripts/lunr/min/lunr.kn.min.js +1 -0
  38. ciocore/docsite/assets/javascripts/lunr/min/lunr.ko.min.js +1 -0
  39. ciocore/docsite/assets/javascripts/lunr/min/lunr.multi.min.js +1 -0
  40. ciocore/docsite/assets/javascripts/lunr/min/lunr.nl.min.js +18 -0
  41. ciocore/docsite/assets/javascripts/lunr/min/lunr.no.min.js +18 -0
  42. ciocore/docsite/assets/javascripts/lunr/min/lunr.pt.min.js +18 -0
  43. ciocore/docsite/assets/javascripts/lunr/min/lunr.ro.min.js +18 -0
  44. ciocore/docsite/assets/javascripts/lunr/min/lunr.ru.min.js +18 -0
  45. ciocore/docsite/assets/javascripts/lunr/min/lunr.sa.min.js +1 -0
  46. ciocore/docsite/assets/javascripts/lunr/min/lunr.stemmer.support.min.js +1 -0
  47. ciocore/docsite/assets/javascripts/lunr/min/lunr.sv.min.js +18 -0
  48. ciocore/docsite/assets/javascripts/lunr/min/lunr.ta.min.js +1 -0
  49. ciocore/docsite/assets/javascripts/lunr/min/lunr.te.min.js +1 -0
  50. ciocore/docsite/assets/javascripts/lunr/min/lunr.th.min.js +1 -0
  51. ciocore/docsite/assets/javascripts/lunr/min/lunr.tr.min.js +18 -0
  52. ciocore/docsite/assets/javascripts/lunr/min/lunr.vi.min.js +1 -0
  53. ciocore/docsite/assets/javascripts/lunr/min/lunr.zh.min.js +1 -0
  54. ciocore/docsite/assets/javascripts/lunr/tinyseg.js +206 -0
  55. ciocore/docsite/assets/javascripts/lunr/wordcut.js +6708 -0
  56. ciocore/docsite/assets/javascripts/workers/search.b8dbb3d2.min.js +42 -0
  57. ciocore/docsite/assets/javascripts/workers/search.b8dbb3d2.min.js.map +7 -0
  58. ciocore/docsite/assets/stylesheets/main.3cba04c6.min.css +1 -0
  59. ciocore/docsite/assets/stylesheets/main.3cba04c6.min.css.map +1 -0
  60. ciocore/docsite/assets/stylesheets/palette.06af60db.min.css +1 -0
  61. ciocore/docsite/assets/stylesheets/palette.06af60db.min.css.map +1 -0
  62. ciocore/docsite/cmdline/docs/index.html +871 -0
  63. ciocore/docsite/cmdline/downloader/index.html +934 -0
  64. ciocore/docsite/cmdline/packages/index.html +878 -0
  65. ciocore/docsite/cmdline/uploader/index.html +995 -0
  66. ciocore/docsite/how-to-guides/index.html +869 -0
  67. ciocore/docsite/index.html +895 -0
  68. ciocore/docsite/logo.png +0 -0
  69. ciocore/docsite/objects.inv +0 -0
  70. ciocore/docsite/search/search_index.json +1 -0
  71. ciocore/docsite/sitemap.xml +3 -0
  72. ciocore/docsite/sitemap.xml.gz +0 -0
  73. ciocore/docsite/stylesheets/extra.css +26 -0
  74. ciocore/docsite/stylesheets/tables.css +167 -0
  75. ciocore/downloader/base_downloader.py +644 -0
  76. ciocore/downloader/download_runner_base.py +47 -0
  77. ciocore/downloader/job_downloader.py +119 -0
  78. ciocore/{downloader.py → downloader/legacy_downloader.py} +12 -9
  79. ciocore/downloader/log.py +73 -0
  80. ciocore/downloader/logging_download_runner.py +87 -0
  81. ciocore/downloader/perpetual_downloader.py +63 -0
  82. ciocore/downloader/registry.py +97 -0
  83. ciocore/downloader/reporter.py +135 -0
  84. ciocore/exceptions.py +8 -2
  85. ciocore/file_utils.py +51 -50
  86. ciocore/hardware_set.py +449 -0
  87. ciocore/loggeria.py +89 -20
  88. ciocore/package_environment.py +110 -48
  89. ciocore/package_query.py +182 -0
  90. ciocore/package_tree.py +319 -258
  91. ciocore/retry.py +0 -0
  92. ciocore/uploader/_uploader.py +547 -364
  93. ciocore/uploader/thread_queue_job.py +176 -0
  94. ciocore/uploader/upload_stats/__init__.py +3 -4
  95. ciocore/uploader/upload_stats/stats_formats.py +10 -4
  96. ciocore/validator.py +34 -2
  97. ciocore/worker.py +174 -151
  98. ciocore-10.0.0b3.dist-info/METADATA +928 -0
  99. ciocore-10.0.0b3.dist-info/RECORD +128 -0
  100. {ciocore-5.1.1.dist-info → ciocore-10.0.0b3.dist-info}/WHEEL +1 -1
  101. ciocore-10.0.0b3.dist-info/entry_points.txt +2 -0
  102. tests/instance_type_fixtures.py +175 -0
  103. tests/package_fixtures.py +205 -0
  104. tests/test_api_client.py +297 -12
  105. tests/test_base_downloader.py +104 -0
  106. tests/test_cli.py +149 -0
  107. tests/test_common.py +1 -7
  108. tests/test_config.py +40 -18
  109. tests/test_data.py +162 -173
  110. tests/test_downloader.py +118 -0
  111. tests/test_hardware_set.py +139 -0
  112. tests/test_job_downloader.py +213 -0
  113. tests/test_package_query.py +38 -0
  114. tests/test_package_tree.py +91 -291
  115. tests/test_submit.py +44 -18
  116. tests/test_uploader.py +1 -4
  117. ciocore/__about__.py +0 -10
  118. ciocore/cli/conductor.py +0 -191
  119. ciocore/compat.py +0 -15
  120. ciocore-5.1.1.data/scripts/conductor +0 -19
  121. ciocore-5.1.1.data/scripts/conductor.bat +0 -13
  122. ciocore-5.1.1.dist-info/METADATA +0 -408
  123. ciocore-5.1.1.dist-info/RECORD +0 -47
  124. tests/mocks/api_client_mock.py +0 -51
  125. /ciocore/{cli → downloader}/__init__.py +0 -0
  126. {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
- file progress: {self.file_progress}
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()