qarnot 2.14.5__tar.gz → 2.15.0__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.
Files changed (78) hide show
  1. {qarnot-2.14.5/qarnot.egg-info → qarnot-2.15.0}/PKG-INFO +1 -1
  2. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot/_util.py +1 -6
  3. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot/_version.py +3 -3
  4. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot/bucket.py +59 -22
  5. {qarnot-2.14.5 → qarnot-2.15.0/qarnot.egg-info}/PKG-INFO +1 -1
  6. {qarnot-2.14.5 → qarnot-2.15.0}/requirements.txt +2 -2
  7. {qarnot-2.14.5 → qarnot-2.15.0}/LICENSE +0 -0
  8. {qarnot-2.14.5 → qarnot-2.15.0}/MANIFEST.in +0 -0
  9. {qarnot-2.14.5 → qarnot-2.15.0}/README.rst +0 -0
  10. {qarnot-2.14.5 → qarnot-2.15.0}/doc/Makefile +0 -0
  11. {qarnot-2.14.5 → qarnot-2.15.0}/doc/make.bat +0 -0
  12. {qarnot-2.14.5 → qarnot-2.15.0}/doc/source/_static/qarnot.png +0 -0
  13. {qarnot-2.14.5 → qarnot-2.15.0}/doc/source/api/compute/computeindex.rst +0 -0
  14. {qarnot-2.14.5 → qarnot-2.15.0}/doc/source/api/compute/hardware_constraint.rst +0 -0
  15. {qarnot-2.14.5 → qarnot-2.15.0}/doc/source/api/compute/job.rst +0 -0
  16. {qarnot-2.14.5 → qarnot-2.15.0}/doc/source/api/compute/paginate.rst +0 -0
  17. {qarnot-2.14.5 → qarnot-2.15.0}/doc/source/api/compute/pool.rst +0 -0
  18. {qarnot-2.14.5 → qarnot-2.15.0}/doc/source/api/compute/privileges.rst +0 -0
  19. {qarnot-2.14.5 → qarnot-2.15.0}/doc/source/api/compute/retry_settings.rst +0 -0
  20. {qarnot-2.14.5 → qarnot-2.15.0}/doc/source/api/compute/scheduling_type.rst +0 -0
  21. {qarnot-2.14.5 → qarnot-2.15.0}/doc/source/api/compute/status.rst +0 -0
  22. {qarnot-2.14.5 → qarnot-2.15.0}/doc/source/api/compute/task.rst +0 -0
  23. {qarnot-2.14.5 → qarnot-2.15.0}/doc/source/api/connection.rst +0 -0
  24. {qarnot-2.14.5 → qarnot-2.15.0}/doc/source/api/exceptions.rst +0 -0
  25. {qarnot-2.14.5 → qarnot-2.15.0}/doc/source/api/storage/advanced_bucket.rst +0 -0
  26. {qarnot-2.14.5 → qarnot-2.15.0}/doc/source/api/storage/bucket.rst +0 -0
  27. {qarnot-2.14.5 → qarnot-2.15.0}/doc/source/api/storage/storage.rst +0 -0
  28. {qarnot-2.14.5 → qarnot-2.15.0}/doc/source/api/storage/storageindex.rst +0 -0
  29. {qarnot-2.14.5 → qarnot-2.15.0}/doc/source/basic.rst +0 -0
  30. {qarnot-2.14.5 → qarnot-2.15.0}/doc/source/conf.py +0 -0
  31. {qarnot-2.14.5 → qarnot-2.15.0}/doc/source/index.rst +0 -0
  32. {qarnot-2.14.5 → qarnot-2.15.0}/doc/source/installation.rst +0 -0
  33. {qarnot-2.14.5 → qarnot-2.15.0}/doc/source/qarnot.rst +0 -0
  34. {qarnot-2.14.5 → qarnot-2.15.0}/pyproject.toml +0 -0
  35. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot/__init__.py +0 -0
  36. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot/_filter.py +0 -0
  37. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot/_retry.py +0 -0
  38. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot/advanced_bucket.py +0 -0
  39. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot/connection.py +0 -0
  40. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot/error.py +0 -0
  41. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot/exceptions.py +0 -0
  42. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot/forced_network_rule.py +0 -0
  43. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot/hardware_constraint.py +0 -0
  44. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot/helper.py +0 -0
  45. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot/job.py +0 -0
  46. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot/paginate.py +0 -0
  47. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot/pool.py +0 -0
  48. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot/privileges.py +0 -0
  49. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot/retry_settings.py +0 -0
  50. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot/scheduling_type.py +0 -0
  51. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot/secrets.py +0 -0
  52. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot/status.py +0 -0
  53. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot/storage.py +0 -0
  54. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot/task.py +0 -0
  55. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot.egg-info/SOURCES.txt +0 -0
  56. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot.egg-info/dependency_links.txt +0 -0
  57. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot.egg-info/requires.txt +0 -0
  58. {qarnot-2.14.5 → qarnot-2.15.0}/qarnot.egg-info/top_level.txt +0 -0
  59. {qarnot-2.14.5 → qarnot-2.15.0}/requirements-doc.txt +0 -0
  60. {qarnot-2.14.5 → qarnot-2.15.0}/requirements-lint.txt +0 -0
  61. {qarnot-2.14.5 → qarnot-2.15.0}/requirements-optional.txt +0 -0
  62. {qarnot-2.14.5 → qarnot-2.15.0}/requirements-test.txt +0 -0
  63. {qarnot-2.14.5 → qarnot-2.15.0}/setup.cfg +0 -0
  64. {qarnot-2.14.5 → qarnot-2.15.0}/setup.py +0 -0
  65. {qarnot-2.14.5 → qarnot-2.15.0}/test/test_advanced_bucket.py +0 -0
  66. {qarnot-2.14.5 → qarnot-2.15.0}/test/test_bucket.py +0 -0
  67. {qarnot-2.14.5 → qarnot-2.15.0}/test/test_connection.py +0 -0
  68. {qarnot-2.14.5 → qarnot-2.15.0}/test/test_hardware_constraints.py +0 -0
  69. {qarnot-2.14.5 → qarnot-2.15.0}/test/test_import.py +0 -0
  70. {qarnot-2.14.5 → qarnot-2.15.0}/test/test_job.py +0 -0
  71. {qarnot-2.14.5 → qarnot-2.15.0}/test/test_paginate.py +0 -0
  72. {qarnot-2.14.5 → qarnot-2.15.0}/test/test_pool.py +0 -0
  73. {qarnot-2.14.5 → qarnot-2.15.0}/test/test_retry.py +0 -0
  74. {qarnot-2.14.5 → qarnot-2.15.0}/test/test_secrets.py +0 -0
  75. {qarnot-2.14.5 → qarnot-2.15.0}/test/test_status.py +0 -0
  76. {qarnot-2.14.5 → qarnot-2.15.0}/test/test_task.py +0 -0
  77. {qarnot-2.14.5 → qarnot-2.15.0}/test/test_util.py +0 -0
  78. {qarnot-2.14.5 → qarnot-2.15.0}/versioneer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: qarnot
3
- Version: 2.14.5
3
+ Version: 2.15.0
4
4
  Summary: Qarnot Computing SDK
5
5
  Home-page: https://computing.qarnot.com
6
6
  Author: Qarnot computing
@@ -20,11 +20,6 @@ from http.client import responses
20
20
 
21
21
  import re
22
22
 
23
- _IS_PY2 = bytes is str
24
-
25
- if not _IS_PY2:
26
- unicode = str
27
-
28
23
 
29
24
  def copy_docs(docs_source):
30
25
  def decorator(obj):
@@ -43,7 +38,7 @@ def decode(string, encoding='utf-8'):
43
38
 
44
39
  def is_string(x):
45
40
  """Check if x is a string (bytes or unicode)."""
46
- return isinstance(x, (str, unicode))
41
+ return isinstance(x, (str, bytes))
47
42
 
48
43
 
49
44
  def parse_to_timespan_string(value):
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2024-03-29T14:48:51+0100",
11
+ "date": "2024-08-27T11:29:32+0200",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "ff28a98ad04060443b7c6b1f487e492c61e31be1",
15
- "version": "v2.14.5"
14
+ "full-revisionid": "8fe176158583e7c2db929a8a25031075991e9e36",
15
+ "version": "v2.15.0"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -242,6 +242,64 @@ class Bucket(Storage): # pylint: disable=W0223
242
242
  bucket = self._connection.s3resource.Bucket(self._uuid)
243
243
  return bucket.objects.filter(Prefix=directory)
244
244
 
245
+ def sync_remote_to_local(self, local_directoy, remote_directory=None):
246
+ """Synchronize a remote directory to a local directory.
247
+
248
+ :param str local_directoy: The local directory to use for synchronization
249
+ :param str remote_directory: path of the directory on remote node (defaults to whole bucket)
250
+
251
+ .. warning::
252
+ Distant changes are reflected on the local filesystem, a file not present on the
253
+ bucket but in the local directory might be deleted from the local filesystem.
254
+
255
+ .. note::
256
+ The following parameters are used to determine whether
257
+ synchronization is required :
258
+
259
+ * name
260
+ * size
261
+ * sha1sum
262
+ """
263
+
264
+ def get_key_for_local(remote_key: str) -> str:
265
+ if remote_directory:
266
+ return removeprefix(remote_key, remote_directory).lstrip('/')
267
+ return remote_key.lstrip('/')
268
+
269
+ def removeprefix(target_str: str, prefix: str) -> str:
270
+ if target_str.startswith(prefix):
271
+ return target_str[len(prefix):]
272
+ else:
273
+ return target_str[:]
274
+
275
+ try:
276
+ if remote_directory:
277
+ entries = self.directory(remote_directory)
278
+ else:
279
+ entries = self.list_files()
280
+
281
+ list_files_only = [x for x in entries if not x.key.endswith('/')]
282
+ list_directories_only = [x for x in entries if x.key.endswith('/')]
283
+ except self._connection.s3resource.meta.client.exceptions.NoSuchBucket as err:
284
+ raise MissingBucketException("Cannot synchronize. Bucket {} not found.".format(err.response['Error']['BucketName'])) from err
285
+
286
+ for directory in list_directories_only:
287
+ if not os.path.isdir(os.path.join(local_directoy, get_key_for_local(directory.key))):
288
+ os.makedirs(os.path.join(local_directoy, get_key_for_local(directory.key)), exist_ok=True)
289
+
290
+ for _, dupes in groupby(sorted(list_files_only, key=attrgetter('e_tag')), attrgetter('e_tag')):
291
+ file_info = next(dupes)
292
+ first_file = os.path.join(local_directoy, get_key_for_local(file_info.key))
293
+ self.get_file(file_info.get()['Body'], local=first_file) # avoids making a useless HEAD request
294
+
295
+ for dupe in dupes:
296
+ local = os.path.join(local_directoy, get_key_for_local(dupe.key))
297
+ directory = os.path.dirname(local)
298
+ if not os.path.exists(directory):
299
+ os.makedirs(directory)
300
+ if (os.path.abspath(os.path.realpath(local)) is not os.path.abspath(os.path.realpath(first_file))):
301
+ shutil.copy(first_file, local)
302
+
245
303
  def sync_directory(self, directory, verbose=False, remote=None):
246
304
  """Synchronize a local directory with the remote buckets.
247
305
 
@@ -433,28 +491,7 @@ class Bucket(Storage): # pylint: disable=W0223
433
491
 
434
492
  @_util.copy_docs(Storage.get_all_files)
435
493
  def get_all_files(self, output_dir, progress=None):
436
- try:
437
- list_files_only = [x for x in self.list_files() if not x.key.endswith('/')]
438
- list_directories_only = [x for x in self.list_files() if x.key.endswith('/')]
439
- except self._connection.s3resource.meta.client.exceptions.NoSuchBucket as err:
440
- raise MissingBucketException("Cannot get files. Bucket {} not found.".format(err.response['Error']['BucketName'])) from err
441
-
442
- for directory in list_directories_only:
443
- if not os.path.isdir(os.path.join(output_dir, directory.key.lstrip('/'))):
444
- os.makedirs(os.path.join(output_dir, directory.key.lstrip('/')))
445
-
446
- for _, dupes in groupby(sorted(list_files_only, key=attrgetter('e_tag')), attrgetter('e_tag')):
447
- file_info = next(dupes)
448
- first_file = os.path.join(output_dir, file_info.key.lstrip('/'))
449
- self.get_file(file_info.get()['Body'], local=first_file) # avoids making a useless HEAD request
450
-
451
- for dupe in dupes:
452
- local = os.path.join(output_dir, dupe.key.lstrip('/'))
453
- directory = os.path.dirname(local)
454
- if not os.path.exists(directory):
455
- os.makedirs(directory)
456
- if (os.path.abspath(os.path.realpath(local)) is not os.path.abspath(os.path.realpath(first_file))):
457
- shutil.copy(first_file, local)
494
+ self.sync_remote_to_local(output_dir, None)
458
495
 
459
496
  @_util.copy_docs(Storage.get_file)
460
497
  def get_file(self, remote, local=None, progress=None):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: qarnot
3
- Version: 2.14.5
3
+ Version: 2.15.0
4
4
  Summary: Qarnot Computing SDK
5
5
  Home-page: https://computing.qarnot.com
6
6
  Author: Qarnot computing
@@ -1,6 +1,6 @@
1
- requests==2.27.1
1
+ requests==2.32.3
2
2
  boto3==1.21.38
3
3
  wheel==0.38.1
4
4
  deprecation==2.1.0
5
5
  simplejson==3.18.3
6
- setuptools==69.1.1
6
+ setuptools==70.3.0
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes