bluer-objects 6.139.1__tar.gz → 6.155.1__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 bluer-objects might be problematic. Click here for more details.

Files changed (165) hide show
  1. {bluer_objects-6.139.1/bluer_objects.egg-info → bluer_objects-6.155.1}/PKG-INFO +3 -2
  2. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/README.md +1 -1
  3. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/__init__.py +1 -1
  4. bluer_objects-6.155.1/bluer_objects/config.env +5 -0
  5. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/env.py +7 -0
  6. bluer_objects-6.155.1/bluer_objects/mlflow/logging.py +87 -0
  7. bluer_objects-6.155.1/bluer_objects/sample.env +9 -0
  8. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/storage/__init__.py +4 -1
  9. bluer_objects-6.155.1/bluer_objects/storage/s3.py +186 -0
  10. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/tests/test_env.py +13 -3
  11. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/tests/test_file_load_save.py +0 -1
  12. bluer_objects-6.155.1/bluer_objects/tests/test_storage_s3.py +67 -0
  13. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/tests/test_storage_webdav_request.py +3 -0
  14. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/tests/test_storage_webdav_zip.py +3 -0
  15. {bluer_objects-6.139.1 → bluer_objects-6.155.1/bluer_objects.egg-info}/PKG-INFO +3 -2
  16. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects.egg-info/SOURCES.txt +2 -0
  17. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects.egg-info/requires.txt +1 -0
  18. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/requirements.txt +1 -0
  19. bluer_objects-6.139.1/bluer_objects/config.env +0 -3
  20. bluer_objects-6.139.1/bluer_objects/mlflow/logging.py +0 -81
  21. bluer_objects-6.139.1/bluer_objects/sample.env +0 -5
  22. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/LICENSE +0 -0
  23. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/MANIFEST.in +0 -0
  24. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/abcli.sh +0 -0
  25. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/actions.sh +0 -0
  26. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/aka.sh +0 -0
  27. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/alias.sh +0 -0
  28. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/bluer_objects.sh +0 -0
  29. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/clone.sh +0 -0
  30. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/create_test_asset.sh +0 -0
  31. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/download.sh +0 -0
  32. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/file.sh +0 -0
  33. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/gif.sh +0 -0
  34. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/host.sh +0 -0
  35. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/ls.sh +0 -0
  36. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/metadata/get.sh +0 -0
  37. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/metadata/post.sh +0 -0
  38. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/metadata.sh +0 -0
  39. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/mlflow/browse.sh +0 -0
  40. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/mlflow/cache.sh +0 -0
  41. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/mlflow/deploy.sh +0 -0
  42. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/mlflow/list_registered_models.sh +0 -0
  43. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/mlflow/log_artifacts.sh +0 -0
  44. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/mlflow/log_run.sh +0 -0
  45. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/mlflow/run.sh +0 -0
  46. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/mlflow/tags/clone.sh +0 -0
  47. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/mlflow/tags/get.sh +0 -0
  48. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/mlflow/tags/search.sh +0 -0
  49. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/mlflow/tags/set.sh +0 -0
  50. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/mlflow/tags.sh +0 -0
  51. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/mlflow/test.sh +0 -0
  52. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/mlflow/transition.sh +0 -0
  53. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/mlflow.sh +0 -0
  54. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/object.sh +0 -0
  55. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/select.sh +0 -0
  56. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/storage/clear.sh +0 -0
  57. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/storage/download_file.sh +0 -0
  58. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/storage/exists.sh +0 -0
  59. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/storage/list.sh +0 -0
  60. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/storage/rm.sh +0 -0
  61. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/storage/status.sh +0 -0
  62. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/storage.sh +0 -0
  63. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/tests/README.sh +0 -0
  64. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/tests/clone.sh +0 -0
  65. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/tests/create_test_asset.sh +0 -0
  66. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/tests/gif.sh +0 -0
  67. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/tests/help.sh +0 -0
  68. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/tests/host.sh +0 -0
  69. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/tests/ls.sh +0 -0
  70. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/tests/metadata.sh +0 -0
  71. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/tests/mlflow_cache.sh +0 -0
  72. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/tests/mlflow_logging.sh +0 -0
  73. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/tests/mlflow_tags.sh +0 -0
  74. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/tests/mlflow_test.sh +0 -0
  75. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/tests/storage.sh +0 -0
  76. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/tests/version.sh +0 -0
  77. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/.abcli/upload.sh +0 -0
  78. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/README/__init__.py +0 -0
  79. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/README/functions.py +0 -0
  80. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/README/items.py +0 -0
  81. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/__main__.py +0 -0
  82. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/file/__init__.py +0 -0
  83. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/file/__main__.py +0 -0
  84. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/file/classes.py +0 -0
  85. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/file/functions.py +0 -0
  86. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/file/load.py +0 -0
  87. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/file/save.py +0 -0
  88. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/graphics/__init__.py +0 -0
  89. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/graphics/__main__.py +0 -0
  90. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/graphics/frame.py +0 -0
  91. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/graphics/gif.py +0 -0
  92. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/graphics/screen.py +0 -0
  93. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/graphics/signature.py +0 -0
  94. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/graphics/text.py +0 -0
  95. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/help/__init__.py +0 -0
  96. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/help/__main__.py +0 -0
  97. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/help/clone.py +0 -0
  98. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/help/create_test_asset.py +0 -0
  99. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/help/download.py +0 -0
  100. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/help/functions.py +0 -0
  101. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/help/gif.py +0 -0
  102. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/help/host.py +0 -0
  103. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/help/ls.py +0 -0
  104. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/help/metadata.py +0 -0
  105. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/help/mlflow/__init__.py +0 -0
  106. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/help/mlflow/cache.py +0 -0
  107. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/help/mlflow/tags.py +0 -0
  108. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/help/upload.py +0 -0
  109. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/host/__init__.py +0 -0
  110. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/host/__main__.py +0 -0
  111. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/host/functions.py +0 -0
  112. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/logger/__init__.py +0 -0
  113. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/logger/matrix.py +0 -0
  114. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/markdown.py +0 -0
  115. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/metadata/__init__.py +0 -0
  116. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/metadata/__main__.py +0 -0
  117. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/metadata/enums.py +0 -0
  118. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/metadata/get.py +0 -0
  119. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/metadata/post.py +0 -0
  120. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/mlflow/__init__.py +0 -0
  121. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/mlflow/__main__.py +0 -0
  122. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/mlflow/cache.py +0 -0
  123. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/mlflow/models.py +0 -0
  124. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/mlflow/objects.py +0 -0
  125. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/mlflow/runs.py +0 -0
  126. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/mlflow/tags.py +0 -0
  127. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/mlflow/testing.py +0 -0
  128. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/objects.py +0 -0
  129. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/path.py +0 -0
  130. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/storage/WebDAV.py +0 -0
  131. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/storage/WebDAVrequest.py +0 -0
  132. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/storage/WebDAVzip.py +0 -0
  133. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/storage/__main__.py +0 -0
  134. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/storage/base.py +0 -0
  135. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/testing/__init__.py +0 -0
  136. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/testing/__main__.py +0 -0
  137. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/testing/functions.py +0 -0
  138. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/tests/__init__.py +0 -0
  139. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/tests/test_README.py +0 -0
  140. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/tests/test_file_download.py +0 -0
  141. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/tests/test_file_load_save_text.py +0 -0
  142. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/tests/test_fullname.py +0 -0
  143. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/tests/test_graphics.py +0 -0
  144. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/tests/test_graphics_frame.py +0 -0
  145. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/tests/test_graphics_gif.py +0 -0
  146. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/tests/test_graphics_screen.py +0 -0
  147. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/tests/test_graphics_signature.py +0 -0
  148. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/tests/test_graphics_text.py +0 -0
  149. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/tests/test_logger.py +0 -0
  150. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/tests/test_logger_matrix.py +0 -0
  151. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/tests/test_markdown.py +0 -0
  152. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/tests/test_metadata.py +0 -0
  153. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/tests/test_mlflow.py +0 -0
  154. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/tests/test_objects.py +0 -0
  155. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/tests/test_path.py +0 -0
  156. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/tests/test_storage.py +0 -0
  157. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/tests/test_storage_base.py +0 -0
  158. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/tests/test_testing.py +0 -0
  159. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/tests/test_version.py +0 -0
  160. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects/urls.py +0 -0
  161. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects.egg-info/dependency_links.txt +0 -0
  162. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/bluer_objects.egg-info/top_level.txt +0 -0
  163. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/pyproject.toml +0 -0
  164. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/setup.cfg +0 -0
  165. {bluer_objects-6.139.1 → bluer_objects-6.155.1}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bluer_objects
3
- Version: 6.139.1
3
+ Version: 6.155.1
4
4
  Summary: 🌀 Object management in Bash.
5
5
  Home-page: https://github.com/kamangir/bluer-objects
6
6
  Author: Arash Abadpour (Kamangir)
@@ -12,6 +12,7 @@ Classifier: Operating System :: OS Independent
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
14
  Requires-Dist: bluer_ai
15
+ Requires-Dist: boto3
15
16
  Requires-Dist: webdavclient3
16
17
  Requires-Dist: dill
17
18
  Requires-Dist: mlflow
@@ -63,6 +64,6 @@ pip install bluer-objects
63
64
 
64
65
  [![pylint](https://github.com/kamangir/bluer-objects/actions/workflows/pylint.yml/badge.svg)](https://github.com/kamangir/bluer-objects/actions/workflows/pylint.yml) [![pytest](https://github.com/kamangir/bluer-objects/actions/workflows/pytest.yml/badge.svg)](https://github.com/kamangir/bluer-objects/actions/workflows/pytest.yml) [![bashtest](https://github.com/kamangir/bluer-objects/actions/workflows/bashtest.yml/badge.svg)](https://github.com/kamangir/bluer-objects/actions/workflows/bashtest.yml) [![PyPI version](https://img.shields.io/pypi/v/bluer-objects.svg)](https://pypi.org/project/bluer-objects/) [![PyPI - Downloads](https://img.shields.io/pypi/dd/bluer-objects)](https://pypistats.org/packages/bluer-objects)
65
66
 
66
- built by 🌀 [`bluer README`](https://github.com/kamangir/bluer-objects/tree/main/bluer_objects/README), based on 🌀 [`bluer_objects-6.139.1`](https://github.com/kamangir/bluer-objects).
67
+ built by 🌀 [`bluer README`](https://github.com/kamangir/bluer-objects/tree/main/bluer_objects/README), based on 🌀 [`bluer_objects-6.155.1`](https://github.com/kamangir/bluer-objects).
67
68
 
68
69
  built by 🌀 [`blueness-3.118.1`](https://github.com/kamangir/blueness).
@@ -30,4 +30,4 @@ pip install bluer-objects
30
30
 
31
31
  [![pylint](https://github.com/kamangir/bluer-objects/actions/workflows/pylint.yml/badge.svg)](https://github.com/kamangir/bluer-objects/actions/workflows/pylint.yml) [![pytest](https://github.com/kamangir/bluer-objects/actions/workflows/pytest.yml/badge.svg)](https://github.com/kamangir/bluer-objects/actions/workflows/pytest.yml) [![bashtest](https://github.com/kamangir/bluer-objects/actions/workflows/bashtest.yml/badge.svg)](https://github.com/kamangir/bluer-objects/actions/workflows/bashtest.yml) [![PyPI version](https://img.shields.io/pypi/v/bluer-objects.svg)](https://pypi.org/project/bluer-objects/) [![PyPI - Downloads](https://img.shields.io/pypi/dd/bluer-objects)](https://pypistats.org/packages/bluer-objects)
32
32
 
33
- built by 🌀 [`bluer README`](https://github.com/kamangir/bluer-objects/tree/main/bluer_objects/README), based on 🌀 [`bluer_objects-6.139.1`](https://github.com/kamangir/bluer-objects).
33
+ built by 🌀 [`bluer README`](https://github.com/kamangir/bluer-objects/tree/main/bluer_objects/README), based on 🌀 [`bluer_objects-6.155.1`](https://github.com/kamangir/bluer-objects).
@@ -4,7 +4,7 @@ ICON = "🌀"
4
4
 
5
5
  DESCRIPTION = f"{ICON} Object management in Bash."
6
6
 
7
- VERSION = "6.139.1"
7
+ VERSION = "6.155.1"
8
8
 
9
9
  REPO_NAME = "bluer-objects"
10
10
 
@@ -0,0 +1,5 @@
1
+ ABCLI_MLFLOW_EXPERIMENT_PREFIX=experiment/
2
+
3
+ S3_STORAGE_BUCKET=kamangir
4
+
5
+ BLUER_OBJECTS_STORAGE_INTERFACE=s3
@@ -35,6 +35,12 @@ DUMMY_TEXT = "This is some dummy text. This is some dummy text. This is some dum
35
35
 
36
36
  ABCLI_MLFLOW_EXPERIMENT_PREFIX = get_env("ABCLI_MLFLOW_EXPERIMENT_PREFIX")
37
37
 
38
+ S3_STORAGE_BUCKET = get_env("S3_STORAGE_BUCKET")
39
+
40
+ S3_STORAGE_ENDPOINT_URL = get_env("S3_STORAGE_ENDPOINT_URL")
41
+ S3_STORAGE_AWS_ACCESS_KEY_ID = get_env("S3_STORAGE_AWS_ACCESS_KEY_ID")
42
+ S3_STORAGE_AWS_SECRET_ACCESS_KEY = get_env("S3_STORAGE_AWS_SECRET_ACCESS_KEY")
43
+
38
44
  BLUER_OBJECTS_STORAGE_INTERFACE = get_env("BLUER_OBJECTS_STORAGE_INTERFACE")
39
45
 
40
46
  MLFLOW_DEPLOYMENT = get_env("MLFLOW_DEPLOYMENT", "local")
@@ -46,6 +52,7 @@ if MLFLOW_DEPLOYMENT == "local":
46
52
  else:
47
53
  MLFLOW_TRACKING_URI = MLFLOW_DEPLOYMENT
48
54
  os.environ["MLFLOW_TRACKING_URI"] = MLFLOW_TRACKING_URI
55
+ MLFLOW_LOG_ARTIFACTS = "arvan" not in MLFLOW_DEPLOYMENT
49
56
 
50
57
  WEBDAV_HOSTNAME = get_env("WEBDAV_HOSTNAME")
51
58
  WEBDAV_LOGIN = get_env("WEBDAV_LOGIN")
@@ -0,0 +1,87 @@
1
+ from typing import Dict
2
+ import os
3
+ import glob
4
+ import mlflow
5
+
6
+ from blueness import module
7
+ from bluer_options.logger import crash_report
8
+
9
+ from bluer_objects import file, objects, NAME, env
10
+ from bluer_objects.mlflow.runs import start_run, end_run
11
+ from bluer_objects.logger import logger
12
+
13
+ NAME = module.name(__file__, NAME)
14
+
15
+
16
+ def log_artifacts(
17
+ object_name: str,
18
+ model_name: str = "",
19
+ ) -> bool:
20
+ if not start_run(object_name):
21
+ return False
22
+
23
+ object_path = objects.object_path(object_name, create=True)
24
+
25
+ if env.MLFLOW_LOG_ARTIFACTS:
26
+ try:
27
+ mlflow.log_artifacts(object_path)
28
+
29
+ logger.info("⬆️ {}".format(object_name))
30
+
31
+ # https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.register_model
32
+ # https://stackoverflow.com/a/71447758/17619982
33
+ if model_name:
34
+ mv = mlflow.register_model(
35
+ "runs:/{}".format(mlflow.active_run().info.run_id),
36
+ model_name,
37
+ await_registration_for=0,
38
+ )
39
+
40
+ logger.info("*️⃣ {} -> {}.{}".format(object_name, mv.name, mv.version))
41
+
42
+ except:
43
+ crash_report(f"{NAME}.log_artifacts({object_name})")
44
+ return False
45
+ else:
46
+ logger.info("skipped log artifacts.")
47
+
48
+ return end_run(object_name)
49
+
50
+
51
+ def log_run(object_name: str) -> bool:
52
+ if not start_run(object_name):
53
+ return False
54
+
55
+ object_path = objects.object_path(object_name, create=True)
56
+
57
+ if env.MLFLOW_LOG_ARTIFACTS:
58
+ counts: Dict[str, int] = {}
59
+ skipped_count = 0
60
+ for extension in "dot,gif,jpeg,jpg,json,png,sh,xml,yaml".split(","):
61
+ for filename in glob.glob(
62
+ os.path.join(object_path, f"*.{extension}"),
63
+ ):
64
+ filename_name = file.name(filename)
65
+
66
+ counts[len(filename_name)] = counts.get(len(filename_name), 0) + 1
67
+
68
+ if any(
69
+ [
70
+ file.size(filename) > 10 * 1024 * 1024,
71
+ filename_name.startswith("thumbnail"),
72
+ counts[len(filename_name)] > 20,
73
+ ]
74
+ ):
75
+ logger.info(f"skipping {filename}")
76
+ skipped_count += 1
77
+ continue
78
+
79
+ mlflow.log_artifact(filename)
80
+ logger.info(f"⬆️ {filename}")
81
+
82
+ if skipped_count:
83
+ logger.info(f"skipped {skipped_count:,} file(s).")
84
+ else:
85
+ logger.info("skipped log artifacts.")
86
+
87
+ return end_run(object_name)
@@ -0,0 +1,9 @@
1
+ S3_STORAGE_ENDPOINT_URL=
2
+ S3_STORAGE_AWS_ACCESS_KEY_ID=
3
+ S3_STORAGE_AWS_SECRET_ACCESS_KEY=
4
+
5
+ MLFLOW_DEPLOYMENT=local
6
+
7
+ WEBDAV_HOSTNAME=
8
+ WEBDAV_LOGIN=
9
+ WEBDAV_PASSWORD=
@@ -1,5 +1,6 @@
1
1
  from typing import Tuple, List
2
2
 
3
+ from bluer_objects.storage.s3 import S3Interface
3
4
  from bluer_objects.storage.base import StorageInterface
4
5
  from bluer_objects.storage.WebDAV import WebDAVInterface
5
6
  from bluer_objects.storage.WebDAVrequest import WebDAVRequestInterface
@@ -9,7 +10,9 @@ from bluer_objects.logger import logger
9
10
 
10
11
  interface = StorageInterface()
11
12
 
12
- if env.BLUER_OBJECTS_STORAGE_INTERFACE == WebDAVInterface.name:
13
+ if env.BLUER_OBJECTS_STORAGE_INTERFACE == S3Interface.name:
14
+ interface = S3Interface()
15
+ elif env.BLUER_OBJECTS_STORAGE_INTERFACE == WebDAVInterface.name:
13
16
  interface = WebDAVInterface()
14
17
  elif env.BLUER_OBJECTS_STORAGE_INTERFACE == WebDAVRequestInterface.name:
15
18
  interface = WebDAVRequestInterface()
@@ -0,0 +1,186 @@
1
+ import boto3
2
+ from botocore.exceptions import ClientError
3
+ import glob
4
+ from typing import Tuple, List
5
+ from xml.etree import ElementTree as ET
6
+ from tqdm import tqdm
7
+ from functools import reduce
8
+
9
+ from bluer_objects.storage.base import StorageInterface
10
+ from bluer_objects import env, file, path
11
+ from bluer_objects import objects
12
+ from bluer_objects.logger import logger
13
+
14
+
15
+ # https://docs.arvancloud.ir/fa/developer-tools/sdk/object-storage/
16
+ class S3Interface(StorageInterface):
17
+ name = "s3"
18
+
19
+ def download(
20
+ self,
21
+ object_name: str,
22
+ filename: str = "",
23
+ log: bool = True,
24
+ ) -> bool:
25
+ if filename:
26
+ local_path = objects.path_of(
27
+ object_name=object_name,
28
+ filename=filename,
29
+ create=True,
30
+ )
31
+
32
+ if not path.create(file.path(local_path)):
33
+ return False
34
+
35
+ try:
36
+ s3_resource = boto3.resource(
37
+ "s3",
38
+ endpoint_url=env.S3_STORAGE_ENDPOINT_URL,
39
+ aws_access_key_id=env.S3_STORAGE_AWS_ACCESS_KEY_ID,
40
+ aws_secret_access_key=env.S3_STORAGE_AWS_SECRET_ACCESS_KEY,
41
+ )
42
+ except Exception as e:
43
+ logger.error(e)
44
+ return False
45
+
46
+ try:
47
+ bucket = s3_resource.Bucket(env.S3_STORAGE_BUCKET)
48
+
49
+ bucket.download_file(
50
+ f"{object_name}/{filename}",
51
+ local_path,
52
+ )
53
+ except ClientError as e:
54
+ if int(e.response["Error"]["Code"]) == 404: # Not found
55
+ return True
56
+ logger.error(e)
57
+ return False
58
+
59
+ return super().download(
60
+ object_name=object_name,
61
+ filename=filename,
62
+ log=log,
63
+ )
64
+
65
+ success, list_of_files = self.ls(
66
+ object_name=object_name,
67
+ where="cloud",
68
+ )
69
+ if not success:
70
+ return False
71
+
72
+ for filename_ in tqdm(list_of_files):
73
+ if not self.download(
74
+ object_name=object_name,
75
+ filename=filename_,
76
+ log=log,
77
+ ):
78
+ return False
79
+
80
+ return True
81
+
82
+ def ls(
83
+ self,
84
+ object_name: str,
85
+ where: str = "local",
86
+ ) -> Tuple[bool, List[str]]:
87
+ if where == "cloud":
88
+ try:
89
+ s3 = boto3.client(
90
+ "s3",
91
+ endpoint_url=env.S3_STORAGE_ENDPOINT_URL,
92
+ aws_access_key_id=env.S3_STORAGE_AWS_ACCESS_KEY_ID,
93
+ aws_secret_access_key=env.S3_STORAGE_AWS_SECRET_ACCESS_KEY,
94
+ )
95
+
96
+ prefix = f"{object_name}/"
97
+
98
+ paginator = s3.get_paginator("list_objects_v2")
99
+ pages = paginator.paginate(
100
+ Bucket=env.S3_STORAGE_BUCKET,
101
+ Prefix=prefix,
102
+ )
103
+ except Exception as e:
104
+ logger.error(e)
105
+ return False, []
106
+
107
+ return True, sorted(
108
+ reduce(
109
+ lambda x, y: x + y,
110
+ [
111
+ [
112
+ obj["Key"].split(prefix, 1)[1]
113
+ for obj in page.get("Contents", [])
114
+ ]
115
+ for page in pages
116
+ ],
117
+ [],
118
+ )
119
+ )
120
+
121
+ return super().ls(
122
+ object_name=object_name,
123
+ where=where,
124
+ )
125
+
126
+ def upload(
127
+ self,
128
+ object_name: str,
129
+ filename: str = "",
130
+ log: bool = True,
131
+ ) -> bool:
132
+ if filename:
133
+ local_path = objects.path_of(
134
+ object_name=object_name,
135
+ filename=filename,
136
+ )
137
+
138
+ try:
139
+ s3_resource = boto3.resource(
140
+ "s3",
141
+ endpoint_url=env.S3_STORAGE_ENDPOINT_URL,
142
+ aws_access_key_id=env.S3_STORAGE_AWS_ACCESS_KEY_ID,
143
+ aws_secret_access_key=env.S3_STORAGE_AWS_SECRET_ACCESS_KEY,
144
+ )
145
+
146
+ bucket = s3_resource.Bucket(env.S3_STORAGE_BUCKET)
147
+
148
+ with open(local_path, "rb") as fp:
149
+ bucket.put_object(
150
+ ACL="private",
151
+ Body=fp,
152
+ Key=f"{object_name}/{filename}",
153
+ )
154
+ except ClientError as e:
155
+ logger.error(e)
156
+ return False
157
+
158
+ return super().upload(
159
+ object_name=object_name,
160
+ filename=filename,
161
+ log=log,
162
+ )
163
+
164
+ object_path = "{}/".format(objects.object_path(object_name=object_name))
165
+ for filename_ in tqdm(
166
+ sorted(
167
+ glob.glob(
168
+ objects.path_of(
169
+ object_name=object_name,
170
+ filename="**",
171
+ ),
172
+ recursive=True,
173
+ )
174
+ )
175
+ ):
176
+ if not file.exists(filename_):
177
+ continue
178
+
179
+ if not self.upload(
180
+ object_name=object_name,
181
+ filename=filename_.split(object_path, 1)[1],
182
+ log=log,
183
+ ):
184
+ return False
185
+
186
+ return True
@@ -1,9 +1,12 @@
1
1
  from bluer_ai.tests.test_env import test_bluer_ai_env
2
2
 
3
3
  from bluer_objects import env
4
- from bluer_objects.storage.WebDAV import WebDAVInterface
5
- from bluer_objects.storage.WebDAVrequest import WebDAVRequestInterface
6
- from bluer_objects.storage.WebDAVzip import WebDAVzipInterface
4
+ from bluer_objects.storage import (
5
+ S3Interface,
6
+ WebDAVInterface,
7
+ WebDAVRequestInterface,
8
+ WebDAVzipInterface,
9
+ )
7
10
 
8
11
 
9
12
  def test_required_env():
@@ -13,7 +16,14 @@ def test_required_env():
13
16
  def test_bluer_objects_env():
14
17
  assert env.ABCLI_MLFLOW_EXPERIMENT_PREFIX
15
18
 
19
+ assert env.S3_STORAGE_BUCKET
20
+
21
+ assert env.S3_STORAGE_ENDPOINT_URL
22
+ assert env.S3_STORAGE_AWS_ACCESS_KEY_ID
23
+ assert env.S3_STORAGE_AWS_SECRET_ACCESS_KEY
24
+
16
25
  assert env.BLUER_OBJECTS_STORAGE_INTERFACE in [
26
+ S3Interface.name,
17
27
  WebDAVInterface.name,
18
28
  WebDAVRequestInterface.name,
19
29
  WebDAVzipInterface.name,
@@ -78,7 +78,6 @@ def test_file_load_save(
78
78
  )
79
79
 
80
80
 
81
- @pytest.mark.unit
82
81
  @pytest.mark.parametrize(
83
82
  ["size", "dtype"],
84
83
  [
@@ -0,0 +1,67 @@
1
+ from bluer_objects import objects
2
+ from bluer_objects.testing import create_test_asset
3
+ from bluer_objects.storage import S3Interface
4
+
5
+
6
+ def test_storage_s3():
7
+ object_name = objects.unique_object("test_storage_s3")
8
+
9
+ assert create_test_asset(
10
+ object_name=object_name,
11
+ depth=10,
12
+ )
13
+
14
+ storage = S3Interface()
15
+
16
+ success, list_of_files_local = storage.ls(
17
+ object_name=object_name,
18
+ where="local",
19
+ )
20
+ assert success
21
+ assert list_of_files_local
22
+
23
+ success, list_of_files_cloud = storage.ls(
24
+ object_name=object_name,
25
+ where="cloud",
26
+ )
27
+ assert success
28
+ assert not list_of_files_cloud
29
+
30
+ for filename in [
31
+ "this.yaml",
32
+ "subfolder/this.yaml",
33
+ "test-00.png",
34
+ ]:
35
+ assert storage.upload(
36
+ object_name=object_name,
37
+ filename=filename,
38
+ )
39
+
40
+ success, list_of_files_cloud = storage.ls(
41
+ object_name=object_name,
42
+ where="cloud",
43
+ )
44
+ assert success
45
+ assert list_of_files_cloud
46
+
47
+ assert storage.upload(object_name=object_name)
48
+
49
+ success, list_of_files_cloud = storage.ls(
50
+ object_name=object_name,
51
+ where="cloud",
52
+ )
53
+ assert success
54
+ assert list_of_files_cloud
55
+ assert list_of_files_cloud == list_of_files_local
56
+
57
+ for filename in [
58
+ "this.yaml",
59
+ "subfolder/this.yaml",
60
+ "test-00.png",
61
+ ]:
62
+ assert storage.download(
63
+ object_name=object_name,
64
+ filename=filename,
65
+ )
66
+
67
+ assert storage.download(object_name=object_name)
@@ -1,8 +1,11 @@
1
+ import pytest
2
+
1
3
  from bluer_objects import objects
2
4
  from bluer_objects.testing import create_test_asset
3
5
  from bluer_objects.storage import WebDAVRequestInterface
4
6
 
5
7
 
8
+ @pytest.mark.skip(reason="nodisk is super slow")
6
9
  def test_storage_webdav_request():
7
10
  object_name = objects.unique_object("test_storage_webdav_request")
8
11
 
@@ -1,8 +1,11 @@
1
+ import pytest
2
+
1
3
  from bluer_objects import objects
2
4
  from bluer_objects.testing import create_test_asset
3
5
  from bluer_objects.storage import WebDAVzipInterface
4
6
 
5
7
 
8
+ @pytest.mark.skip(reason="nodisk is super slow")
6
9
  def test_storage_webdav_zip():
7
10
  object_name = objects.unique_object("test_storage_webdav_zip")
8
11
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bluer_objects
3
- Version: 6.139.1
3
+ Version: 6.155.1
4
4
  Summary: 🌀 Object management in Bash.
5
5
  Home-page: https://github.com/kamangir/bluer-objects
6
6
  Author: Arash Abadpour (Kamangir)
@@ -12,6 +12,7 @@ Classifier: Operating System :: OS Independent
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
14
  Requires-Dist: bluer_ai
15
+ Requires-Dist: boto3
15
16
  Requires-Dist: webdavclient3
16
17
  Requires-Dist: dill
17
18
  Requires-Dist: mlflow
@@ -63,6 +64,6 @@ pip install bluer-objects
63
64
 
64
65
  [![pylint](https://github.com/kamangir/bluer-objects/actions/workflows/pylint.yml/badge.svg)](https://github.com/kamangir/bluer-objects/actions/workflows/pylint.yml) [![pytest](https://github.com/kamangir/bluer-objects/actions/workflows/pytest.yml/badge.svg)](https://github.com/kamangir/bluer-objects/actions/workflows/pytest.yml) [![bashtest](https://github.com/kamangir/bluer-objects/actions/workflows/bashtest.yml/badge.svg)](https://github.com/kamangir/bluer-objects/actions/workflows/bashtest.yml) [![PyPI version](https://img.shields.io/pypi/v/bluer-objects.svg)](https://pypi.org/project/bluer-objects/) [![PyPI - Downloads](https://img.shields.io/pypi/dd/bluer-objects)](https://pypistats.org/packages/bluer-objects)
65
66
 
66
- built by 🌀 [`bluer README`](https://github.com/kamangir/bluer-objects/tree/main/bluer_objects/README), based on 🌀 [`bluer_objects-6.139.1`](https://github.com/kamangir/bluer-objects).
67
+ built by 🌀 [`bluer README`](https://github.com/kamangir/bluer-objects/tree/main/bluer_objects/README), based on 🌀 [`bluer_objects-6.155.1`](https://github.com/kamangir/bluer-objects).
67
68
 
68
69
  built by 🌀 [`blueness-3.118.1`](https://github.com/kamangir/blueness).
@@ -127,6 +127,7 @@ bluer_objects/storage/WebDAVzip.py
127
127
  bluer_objects/storage/__init__.py
128
128
  bluer_objects/storage/__main__.py
129
129
  bluer_objects/storage/base.py
130
+ bluer_objects/storage/s3.py
130
131
  bluer_objects/testing/__init__.py
131
132
  bluer_objects/testing/__main__.py
132
133
  bluer_objects/testing/functions.py
@@ -152,6 +153,7 @@ bluer_objects/tests/test_objects.py
152
153
  bluer_objects/tests/test_path.py
153
154
  bluer_objects/tests/test_storage.py
154
155
  bluer_objects/tests/test_storage_base.py
156
+ bluer_objects/tests/test_storage_s3.py
155
157
  bluer_objects/tests/test_storage_webdav_request.py
156
158
  bluer_objects/tests/test_storage_webdav_zip.py
157
159
  bluer_objects/tests/test_testing.py
@@ -1,4 +1,5 @@
1
1
  bluer_ai
2
+ boto3
2
3
  webdavclient3
3
4
  dill
4
5
  mlflow
@@ -1,5 +1,6 @@
1
1
  bluer_ai
2
2
 
3
+ boto3
3
4
  webdavclient3
4
5
  dill
5
6
  mlflow
@@ -1,3 +0,0 @@
1
- ABCLI_MLFLOW_EXPERIMENT_PREFIX=experiment/
2
-
3
- BLUER_OBJECTS_STORAGE_INTERFACE=webdav-request
@@ -1,81 +0,0 @@
1
- from typing import Dict
2
- import os
3
- import glob
4
- import mlflow
5
-
6
- from blueness import module
7
- from bluer_options.logger import crash_report
8
-
9
- from bluer_objects import file, objects, NAME
10
- from bluer_objects.mlflow.runs import start_run, end_run
11
- from bluer_objects.logger import logger
12
-
13
- NAME = module.name(__file__, NAME)
14
-
15
-
16
- def log_artifacts(
17
- object_name: str,
18
- model_name: str = "",
19
- ) -> bool:
20
- if not start_run(object_name):
21
- return False
22
-
23
- object_path = objects.object_path(object_name, create=True)
24
-
25
- try:
26
- mlflow.log_artifacts(object_path)
27
-
28
- logger.info("⬆️ {}".format(object_name))
29
-
30
- # https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.register_model
31
- # https://stackoverflow.com/a/71447758/17619982
32
- if model_name:
33
- mv = mlflow.register_model(
34
- "runs:/{}".format(mlflow.active_run().info.run_id),
35
- model_name,
36
- await_registration_for=0,
37
- )
38
-
39
- logger.info("*️⃣ {} -> {}.{}".format(object_name, mv.name, mv.version))
40
-
41
- except:
42
- crash_report(f"{NAME}.log_artifacts({object_name})")
43
- return False
44
-
45
- return end_run(object_name)
46
-
47
-
48
- def log_run(object_name: str) -> bool:
49
- if not start_run(object_name):
50
- return False
51
-
52
- object_path = objects.object_path(object_name, create=True)
53
-
54
- counts: Dict[str, int] = {}
55
- skipped_count = 0
56
- for extension in "dot,gif,jpeg,jpg,json,png,sh,xml,yaml".split(","):
57
- for filename in glob.glob(
58
- os.path.join(object_path, f"*.{extension}"),
59
- ):
60
- filename_name = file.name(filename)
61
-
62
- counts[len(filename_name)] = counts.get(len(filename_name), 0) + 1
63
-
64
- if any(
65
- [
66
- file.size(filename) > 10 * 1024 * 1024,
67
- filename_name.startswith("thumbnail"),
68
- counts[len(filename_name)] > 20,
69
- ]
70
- ):
71
- logger.info(f"skipping {filename}")
72
- skipped_count += 1
73
- continue
74
-
75
- mlflow.log_artifact(filename)
76
- logger.info(f"⬆️ {filename}")
77
-
78
- if skipped_count:
79
- logger.info(f"skipped {skipped_count:,} file(s).")
80
-
81
- return end_run(object_name)
@@ -1,5 +0,0 @@
1
- MLFLOW_DEPLOYMENT=local
2
-
3
- WEBDAV_HOSTNAME=
4
- WEBDAV_LOGIN=
5
- WEBDAV_PASSWORD=
File without changes