qmenta-core 4.1.dev710__tar.gz → 4.1.dev711__tar.gz

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 qmenta-core might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: qmenta-core
3
- Version: 4.1.dev710
3
+ Version: 4.1.dev711
4
4
  Summary: QMENTA core library to communicate with the QMENTA platform.
5
5
  License: Proprietary
6
6
  Author: QMENTA
@@ -16,9 +16,10 @@ Classifier: Programming Language :: Python :: 3.12
16
16
  Classifier: Programming Language :: Python :: 3.13
17
17
  Requires-Dist: blinker (>=1.4,<2.0)
18
18
  Requires-Dist: importlib-metadata (>=6.8.0,<7.0.0)
19
+ Requires-Dist: packaging (>=25.0,<26.0)
19
20
  Requires-Dist: python-dotenv (>=1.0.0,<2.0.0)
20
21
  Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
21
- Requires-Dist: qmenta-anon (>=2.0,<3.0)
22
+ Requires-Dist: qmenta-anon (>=2.1.dev377,<3.0)
22
23
  Requires-Dist: requests (>=2.31.0,<3.0.0)
23
24
  Requires-Dist: xdg (>=6.0.0,<7.0.0)
24
25
  Project-URL: Documentation, https://docs.qmenta.com/core/
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "qmenta-core"
3
- version = "4.1.dev710"
3
+ version = "4.1.dev711"
4
4
  description = "QMENTA core library to communicate with the QMENTA platform."
5
5
  license = "Proprietary"
6
6
  authors = ["QMENTA <dev@qmenta.com>"]
@@ -22,20 +22,21 @@ qmenta-auth = 'qmenta.core.auth:main'
22
22
  python = "^3.10"
23
23
  requests = "^2.31.0"
24
24
  pyyaml = "^6.0.1"
25
- qmenta-anon = "^2.0"
25
+ qmenta-anon = "^2.1.dev377"
26
26
  importlib-metadata = "^6.8.0"
27
27
  xdg = "^6.0.0"
28
28
  python-dotenv = "^1.0.0"
29
29
  # We are not requiring the latest blinker 1.6.2 because that is not
30
30
  # available in Google Colab, see EN-1810.
31
31
  blinker = "^1.4"
32
+ packaging = "^25.0"
32
33
 
33
34
  [tool.poetry.group.dev.dependencies]
34
35
  flake8 = "^6.1.0"
35
36
  mypy = "^1.5.1"
36
37
  pytest = "^7.4.0"
37
38
  coverage = {version = "^7.3.0", extras = ["toml"]}
38
-
39
+ pytest-cov = "^6.1.1"
39
40
  sphinx-rtd-theme = "^1.3.0"
40
41
  dom-toml = "^0.6.1"
41
42
  scriv = {version = "^1.3.1", extras = ["toml"]}
@@ -35,11 +35,12 @@ class Needs2FAError(ActionFailedError):
35
35
 
36
36
  @unique
37
37
  class PlatformURL(Enum):
38
- platform = 'platform.qmenta.com'
39
- staging = 'staging.qmenta.com'
40
- test = 'test.qmenta.com'
41
- local_ip = "127.0.0.1:8080"
42
- localhost = "localhost:8080"
38
+ platform = 'https://platform.qmenta.com'
39
+ staging = 'https://staging.qmenta.com'
40
+ test = 'https://test.qmenta.com'
41
+ test_insecure = 'http://test.qmenta.com'
42
+ local_ip = "http://127.0.0.1:8080"
43
+ localhost = "http://localhost:8080"
43
44
 
44
45
 
45
46
  class Auth:
@@ -287,7 +288,7 @@ def validate_url(url: str) -> None:
287
288
  )
288
289
 
289
290
  url_values = [p_url.value for p_url in PlatformURL]
290
- if parsed_url.netloc not in url_values:
291
+ if parsed_url.scheme + '://' + parsed_url.netloc not in url_values:
291
292
  raise ValueError(
292
293
  "base_url must be one of '{}', ".format("', '".join(url_values))
293
294
  + f"not '{parsed_url.netloc}'."
@@ -138,7 +138,7 @@ def parse_response(response: requests.Response) -> Any:
138
138
  def post(
139
139
  auth: Auth, endpoint: str, data: Dict[str, Any] = {},
140
140
  headers: Dict[str, Any] = {}, stream: bool = False,
141
- timeout: float = 30.0
141
+ timeout: float = 60.0
142
142
  ) -> requests.Response:
143
143
  """
144
144
  Post the given data and headers to the specified platform's endpoint.
@@ -95,6 +95,11 @@ class FileInfo:
95
95
  if self.is_result and not self.input_data_type:
96
96
  self.input_data_type = "offline_analysis:1.0"
97
97
 
98
+ if self.input_data_type and ":" not in self.input_data_type:
99
+ raise ValueError(
100
+ "If input_data_type is provided it must include its version"
101
+ )
102
+
98
103
  if self.split_data and self.session_id:
99
104
  # Don't split data when session_id is set
100
105
  self.split_data = False
@@ -148,6 +153,12 @@ class SingleUpload:
148
153
  after the upload finished. When set to False, the ``qm-*.zip`` files
149
154
  that were created by this SingleUpload will be deleted when the upload
150
155
  if finished. Default value: True.
156
+ chunk_size: int
157
+ The maximum size in bytes of each chunk of file to upload.
158
+ Default value: 2**24 == 16 MiB (optimized for GCS Bucket Storage)
159
+ max_retries: int
160
+ Maximum number of retries when uploading a file before raising
161
+ an error. Default value: 5
151
162
 
152
163
  Attributes
153
164
  ----------
@@ -186,12 +197,15 @@ class SingleUpload:
186
197
  anonymise: bool = True,
187
198
  upload_index: int = -1,
188
199
  keep_created_files: bool = True,
200
+ chunk_size: int = 2**24, # 16 MiB
201
+ max_retries: int = 5
189
202
  ) -> None:
190
203
  self.auth = auth
191
204
  self.path = path
192
205
  self.file_info = file_info
193
206
  self.upload_index = upload_index
194
207
  self.keep_created_files = keep_created_files
208
+ self.max_retries = max_retries
195
209
  self._created_files_list: List[str] = []
196
210
 
197
211
  # file_size will be set in _check_type_and_size if the original file
@@ -206,7 +220,7 @@ class SingleUpload:
206
220
  self.upload_filename: str
207
221
 
208
222
  # Optimized for GCS Bucket Storage
209
- self._chunk_size = 2**24 # 16 MiB
223
+ self._chunk_size = chunk_size
210
224
 
211
225
  if os.path.isfile(self.path):
212
226
  self.input_filename = self.path
@@ -472,6 +486,16 @@ class SingleUpload:
472
486
  UploadError
473
487
  platform.ConnectionError
474
488
  """
489
+ def iterate_over_file() -> Generator[Any, Any, Any]:
490
+ with open(self.upload_filename, "rb") as stream:
491
+ while True:
492
+ contents = stream.read(self._chunk_size)
493
+ if not contents:
494
+ break
495
+ else:
496
+ yield contents
497
+ self.bytes_uploaded += len(contents)
498
+
475
499
  assert self.status == UploadStatus.TO_UPLOAD
476
500
  self.status = UploadStatus.UPLOADING
477
501
  self.file_size = prepare.get_zipfile_size(self.upload_filename)
@@ -495,7 +519,6 @@ class SingleUpload:
495
519
  "_pid": self.file_info.project_id,
496
520
  },
497
521
  )
498
-
499
522
  url_response_data = platform.parse_response(url_request_response)
500
523
  signed_url: str = url_response_data["url"]
501
524
  container_id: str = url_response_data["container_id"]
@@ -503,27 +526,14 @@ class SingleUpload:
503
526
  md5_hash: str = self._file_md5(self.upload_filename)
504
527
 
505
528
  # Stream file to signed-url without loading it to memory
506
- max_retries: int = 5
507
529
  completed_upload: bool = False
508
530
  retries_count: int = 0
509
- while not completed_upload and retries_count < max_retries:
510
-
511
- def iterate_over_file() -> Generator[Any, Any, Any]:
512
- with open(self.upload_filename, "rb") as stream:
513
- while True:
514
- contents = stream.read(self._chunk_size)
515
- if not contents:
516
- break
517
- else:
518
- yield contents
519
- self.bytes_uploaded += len(contents)
520
-
531
+ while not completed_upload and retries_count < self.max_retries:
521
532
  upload_response = post(
522
533
  url=signed_url,
523
534
  data=iterate_over_file(),
524
535
  stream=True
525
536
  )
526
-
527
537
  # Verify upload
528
538
  try:
529
539
  self._validate_upload_response(
@@ -531,7 +541,7 @@ class SingleUpload:
531
541
  )
532
542
  except UploadError:
533
543
  retries_count += 1
534
- if retries_count < max_retries:
544
+ if retries_count < self.max_retries:
535
545
  wait_time: int = 2 ** retries_count
536
546
  time.sleep(wait_time)
537
547
  print(
@@ -549,6 +559,11 @@ class SingleUpload:
549
559
  )
550
560
  )
551
561
 
562
+ tool_type = None
563
+ tool_version = None
564
+ if self.file_info.input_data_type:
565
+ tool_type, tool_version = self.file_info.input_data_type.split(":")
566
+
552
567
  verification_response = platform.post(
553
568
  auth=self.auth,
554
569
  endpoint="file_manager/verify_upload_via_url",
@@ -556,6 +571,8 @@ class SingleUpload:
556
571
  "container_id": container_id,
557
572
  "path": fname,
558
573
  "md5": md5_hash,
574
+ "tool_type": tool_type,
575
+ "tool_version": tool_version,
559
576
  },
560
577
  )
561
578
  platform.parse_response(verification_response)