bluer-objects 6.104.1__tar.gz → 6.129.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 (157) hide show
  1. {bluer_objects-6.104.1/bluer_objects.egg-info → bluer_objects-6.129.1}/PKG-INFO +2 -2
  2. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/README.md +1 -1
  3. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/tests/storage.sh +9 -3
  4. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/__init__.py +1 -1
  5. bluer_objects-6.129.1/bluer_objects/config.env +3 -0
  6. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/file/load.py +2 -9
  7. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/file/save.py +1 -19
  8. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/storage/WebDAV.py +0 -7
  9. bluer_objects-6.129.1/bluer_objects/storage/WebDAVrequest.py +346 -0
  10. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/storage/WebDAVzip.py +5 -21
  11. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/storage/__init__.py +3 -0
  12. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/storage/base.py +30 -2
  13. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/tests/test_env.py +2 -0
  14. bluer_objects-6.129.1/bluer_objects/tests/test_file_load_save_text.py +46 -0
  15. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/tests/test_storage.py +8 -21
  16. bluer_objects-6.129.1/bluer_objects/tests/test_storage_base.py +39 -0
  17. bluer_objects-6.129.1/bluer_objects/tests/test_storage_webdav_request.py +72 -0
  18. bluer_objects-6.129.1/bluer_objects/tests/test_storage_webdav_zip.py +39 -0
  19. {bluer_objects-6.104.1 → bluer_objects-6.129.1/bluer_objects.egg-info}/PKG-INFO +2 -2
  20. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects.egg-info/SOURCES.txt +5 -0
  21. bluer_objects-6.104.1/bluer_objects/config.env +0 -3
  22. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/LICENSE +0 -0
  23. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/MANIFEST.in +0 -0
  24. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/abcli.sh +0 -0
  25. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/actions.sh +0 -0
  26. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/aka.sh +0 -0
  27. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/alias.sh +0 -0
  28. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/bluer_objects.sh +0 -0
  29. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/clone.sh +0 -0
  30. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/download.sh +0 -0
  31. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/file.sh +0 -0
  32. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/gif.sh +0 -0
  33. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/host.sh +0 -0
  34. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/ls.sh +0 -0
  35. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/metadata/get.sh +0 -0
  36. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/metadata/post.sh +0 -0
  37. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/metadata.sh +0 -0
  38. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/mlflow/browse.sh +0 -0
  39. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/mlflow/cache.sh +0 -0
  40. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/mlflow/deploy.sh +0 -0
  41. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/mlflow/list_registered_models.sh +0 -0
  42. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/mlflow/log_artifacts.sh +0 -0
  43. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/mlflow/log_run.sh +0 -0
  44. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/mlflow/run.sh +0 -0
  45. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/mlflow/tags/clone.sh +0 -0
  46. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/mlflow/tags/get.sh +0 -0
  47. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/mlflow/tags/search.sh +0 -0
  48. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/mlflow/tags/set.sh +0 -0
  49. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/mlflow/tags.sh +0 -0
  50. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/mlflow/test.sh +0 -0
  51. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/mlflow/transition.sh +0 -0
  52. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/mlflow.sh +0 -0
  53. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/object.sh +0 -0
  54. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/select.sh +0 -0
  55. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/storage/clear.sh +0 -0
  56. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/storage/download_file.sh +0 -0
  57. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/storage/exists.sh +0 -0
  58. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/storage/list.sh +0 -0
  59. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/storage/rm.sh +0 -0
  60. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/storage/status.sh +0 -0
  61. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/storage.sh +0 -0
  62. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/tests/README.sh +0 -0
  63. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/tests/clone.sh +0 -0
  64. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/tests/gif.sh +0 -0
  65. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/tests/help.sh +0 -0
  66. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/tests/host.sh +0 -0
  67. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/tests/ls.sh +0 -0
  68. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/tests/metadata.sh +0 -0
  69. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/tests/mlflow_cache.sh +0 -0
  70. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/tests/mlflow_logging.sh +0 -0
  71. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/tests/mlflow_tags.sh +0 -0
  72. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/tests/mlflow_test.sh +0 -0
  73. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/tests/version.sh +0 -0
  74. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/.abcli/upload.sh +0 -0
  75. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/README/__init__.py +0 -0
  76. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/README/functions.py +0 -0
  77. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/README/items.py +0 -0
  78. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/__main__.py +0 -0
  79. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/env.py +0 -0
  80. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/file/__init__.py +0 -0
  81. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/file/__main__.py +0 -0
  82. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/file/classes.py +0 -0
  83. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/file/functions.py +0 -0
  84. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/graphics/__init__.py +0 -0
  85. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/graphics/__main__.py +0 -0
  86. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/graphics/frame.py +0 -0
  87. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/graphics/gif.py +0 -0
  88. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/graphics/screen.py +0 -0
  89. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/graphics/signature.py +0 -0
  90. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/graphics/text.py +0 -0
  91. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/help/__init__.py +0 -0
  92. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/help/__main__.py +0 -0
  93. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/help/clone.py +0 -0
  94. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/help/download.py +0 -0
  95. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/help/functions.py +0 -0
  96. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/help/gif.py +0 -0
  97. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/help/host.py +0 -0
  98. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/help/ls.py +0 -0
  99. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/help/metadata.py +0 -0
  100. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/help/mlflow/__init__.py +0 -0
  101. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/help/mlflow/cache.py +0 -0
  102. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/help/mlflow/tags.py +0 -0
  103. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/help/upload.py +0 -0
  104. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/host/__init__.py +0 -0
  105. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/host/__main__.py +0 -0
  106. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/host/functions.py +0 -0
  107. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/logger/__init__.py +0 -0
  108. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/logger/matrix.py +0 -0
  109. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/markdown.py +0 -0
  110. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/metadata/__init__.py +0 -0
  111. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/metadata/__main__.py +0 -0
  112. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/metadata/enums.py +0 -0
  113. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/metadata/get.py +0 -0
  114. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/metadata/post.py +0 -0
  115. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/mlflow/__init__.py +0 -0
  116. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/mlflow/__main__.py +0 -0
  117. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/mlflow/cache.py +0 -0
  118. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/mlflow/logging.py +0 -0
  119. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/mlflow/models.py +0 -0
  120. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/mlflow/objects.py +0 -0
  121. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/mlflow/runs.py +0 -0
  122. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/mlflow/tags.py +0 -0
  123. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/mlflow/testing.py +0 -0
  124. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/objects.py +0 -0
  125. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/path.py +0 -0
  126. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/sample.env +0 -0
  127. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/storage/__main__.py +0 -0
  128. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/testing/__init__.py +0 -0
  129. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/testing/__main__.py +0 -0
  130. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/testing/functions.py +0 -0
  131. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/tests/__init__.py +0 -0
  132. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/tests/test_README.py +0 -0
  133. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/tests/test_file_load_save.py +0 -0
  134. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/tests/test_fullname.py +0 -0
  135. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/tests/test_graphics.py +0 -0
  136. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/tests/test_graphics_frame.py +0 -0
  137. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/tests/test_graphics_gif.py +0 -0
  138. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/tests/test_graphics_screen.py +0 -0
  139. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/tests/test_graphics_signature.py +0 -0
  140. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/tests/test_graphics_text.py +0 -0
  141. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/tests/test_logger.py +0 -0
  142. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/tests/test_logger_matrix.py +0 -0
  143. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/tests/test_markdown.py +0 -0
  144. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/tests/test_metadata.py +0 -0
  145. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/tests/test_mlflow.py +0 -0
  146. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/tests/test_objects.py +0 -0
  147. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/tests/test_path.py +0 -0
  148. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/tests/test_testing.py +0 -0
  149. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/tests/test_version.py +0 -0
  150. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects/urls.py +0 -0
  151. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects.egg-info/dependency_links.txt +0 -0
  152. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects.egg-info/requires.txt +0 -0
  153. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/bluer_objects.egg-info/top_level.txt +0 -0
  154. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/pyproject.toml +0 -0
  155. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/requirements.txt +0 -0
  156. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/setup.cfg +0 -0
  157. {bluer_objects-6.104.1 → bluer_objects-6.129.1}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bluer_objects
3
- Version: 6.104.1
3
+ Version: 6.129.1
4
4
  Summary: 🌀 Object management in Bash.
5
5
  Home-page: https://github.com/kamangir/bluer-objects
6
6
  Author: Arash Abadpour (Kamangir)
@@ -63,6 +63,6 @@ pip install bluer-objects
63
63
 
64
64
  [![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
65
 
66
- built by 🌀 [`bluer README`](https://github.com/kamangir/bluer-objects/tree/main/bluer_objects/README), based on 🌀 [`bluer_objects-6.104.1`](https://github.com/kamangir/bluer-objects).
66
+ built by 🌀 [`bluer README`](https://github.com/kamangir/bluer-objects/tree/main/bluer_objects/README), based on 🌀 [`bluer_objects-6.129.1`](https://github.com/kamangir/bluer-objects).
67
67
 
68
68
  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.104.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.129.1`](https://github.com/kamangir/bluer-objects).
@@ -11,10 +11,13 @@ function test_bluer_objects_storage() {
11
11
  create_test_asset \
12
12
  --object_name $object_name
13
13
  [[ $? -ne 0 ]] && return 1
14
+ bluer_ai_hr
14
15
 
15
- # testing upload
16
+ bluer_objects_ls local $object_name
17
+ [[ $? -ne 0 ]] && return 1
16
18
  bluer_ai_hr
17
19
 
20
+ # upload
18
21
  bluer_objects_upload \
19
22
  filename=this.yaml \
20
23
  $object_name
@@ -33,12 +36,15 @@ function test_bluer_objects_storage() {
33
36
  [[ $? -ne 0 ]] && return 1
34
37
  bluer_ai_hr
35
38
 
39
+ bluer_objects_ls cloud $object_name
40
+ [[ $? -ne 0 ]] && return 1
41
+ bluer_ai_hr
42
+
36
43
  # clean-up
37
44
  rm -rfv $object_path
38
45
  bluer_ai_hr
39
46
 
40
- # testing download
41
-
47
+ # download
42
48
  bluer_objects_download \
43
49
  filename=this.yaml \
44
50
  $object_name
@@ -4,7 +4,7 @@ ICON = "🌀"
4
4
 
5
5
  DESCRIPTION = f"{ICON} Object management in Bash."
6
6
 
7
- VERSION = "6.104.1"
7
+ VERSION = "6.129.1"
8
8
 
9
9
  REPO_NAME = "bluer-objects"
10
10
 
@@ -0,0 +1,3 @@
1
+ ABCLI_MLFLOW_EXPERIMENT_PREFIX=experiment/
2
+
3
+ BLUER_OBJECTS_STORAGE_INTERFACE=webdav-request
@@ -149,21 +149,14 @@ def load_matrix(
149
149
  def load_text(
150
150
  filename,
151
151
  ignore_error=False,
152
- count=-1,
153
152
  log=False,
154
153
  ) -> Tuple[bool, List[str]]:
155
154
  success = True
156
155
  text = []
157
156
 
158
157
  try:
159
- if count == -1:
160
- with open(filename, "r") as fp:
161
- text = fp.read()
162
- text = text.split("\n")
163
- else:
164
- # https://stackoverflow.com/a/1767589/10917551
165
- with open(filename) as fp:
166
- text = [next(fp) for _ in range(count)]
158
+ with open(filename, "r") as fp:
159
+ text = fp.read().splitlines()
167
160
  except:
168
161
  success = False
169
162
  if not ignore_error:
@@ -13,7 +13,6 @@ from bluer_options.host import is_jupyter
13
13
  from bluer_objects import NAME
14
14
  from bluer_objects.file.classes import JsonEncoder
15
15
  from bluer_objects.file.functions import path as file_path
16
- from bluer_objects.file.load import load_text
17
16
  from bluer_objects.path import create as path_create
18
17
  from bluer_objects.logger import logger
19
18
 
@@ -214,32 +213,15 @@ def save_matrix(
214
213
  def save_text(
215
214
  filename: str,
216
215
  text: List[str],
217
- if_different: bool = False,
218
216
  log: bool = False,
219
- remove_empty_lines: bool = False,
220
217
  ) -> bool:
221
- if remove_empty_lines:
222
- text = [
223
- line
224
- for line, next_line in zip(text, text[1:] + ["x"])
225
- if line.strip() or next_line.strip()
226
- ]
227
-
228
- if if_different:
229
- _, content = load_text(filename, ignore_error=True)
230
-
231
- if "|".join([line for line in content if line]) == "|".join(
232
- [line for line in text if line]
233
- ):
234
- return True
235
-
236
218
  if not prepare_for_saving(filename):
237
219
  return False
238
220
 
239
221
  success = True
240
222
  try:
241
223
  with open(filename, "w") as fp:
242
- fp.writelines([string + "\n" for string in text])
224
+ fp.writelines(string + "\n" for string in text)
243
225
  except:
244
226
  success = False
245
227
 
@@ -82,13 +82,6 @@ class WebDAVInterface(StorageInterface):
82
82
  log=log,
83
83
  )
84
84
 
85
- def ls(
86
- self,
87
- object_name: str,
88
- where: str = "local",
89
- ) -> Tuple[bool, List[str]]:
90
- assert False, "not implemented"
91
-
92
85
  def upload(
93
86
  self,
94
87
  object_name: str,
@@ -0,0 +1,346 @@
1
+ import requests
2
+ from requests.auth import HTTPBasicAuth
3
+ import glob
4
+ from typing import Tuple, List
5
+ from xml.etree import ElementTree as ET
6
+ from tqdm import tqdm
7
+
8
+ from bluer_objects.storage.base import StorageInterface
9
+ from bluer_objects import env, file, path
10
+ from bluer_objects import objects
11
+ from bluer_objects.logger import logger
12
+
13
+
14
+ # https://chatgpt.com/c/6824cf43-6738-8005-8733-54b6a77f20ee
15
+ class WebDAVRequestInterface(StorageInterface):
16
+ name = "webdav-request"
17
+
18
+ def clear(
19
+ self,
20
+ do_dryrun: bool = True,
21
+ log: bool = True,
22
+ ) -> bool:
23
+ logger.info(
24
+ "{}.clear({})".format(
25
+ self.__class__.__name__,
26
+ "dryrun" if do_dryrun else "",
27
+ )
28
+ )
29
+
30
+ success, list_of_objects = self.list_raw(
31
+ suffix="",
32
+ recursive=False,
33
+ )
34
+ if not success:
35
+ return False
36
+
37
+ count: int = 0
38
+ for thing in tqdm(list_of_objects):
39
+ thing_name = thing.split(f"{env.WEBDAV_LOGIN}/", 1)[1]
40
+ if not thing_name.startswith("test"):
41
+ continue
42
+
43
+ if not thing_name.endswith("/"):
44
+ continue
45
+
46
+ if not self.delete(
47
+ object_name=thing_name.split("/", 1)[0],
48
+ do_dryrun=do_dryrun,
49
+ log=log,
50
+ ):
51
+ return False
52
+
53
+ count += 1
54
+
55
+ logger.info(f"deleted {count} object(s).")
56
+ return True
57
+
58
+ def delete(
59
+ self,
60
+ object_name: str,
61
+ do_dryrun: bool = True,
62
+ log: bool = True,
63
+ ) -> bool:
64
+ if log:
65
+ logger.info(
66
+ "{}.delete({}){}".format(
67
+ self.__class__.__name__,
68
+ object_name,
69
+ " dryrun" if do_dryrun else "",
70
+ )
71
+ )
72
+ if do_dryrun:
73
+ return True
74
+
75
+ try:
76
+ response = requests.request(
77
+ method="DELETE",
78
+ url=f"{env.WEBDAV_HOSTNAME}/{object_name}/",
79
+ auth=HTTPBasicAuth(
80
+ env.WEBDAV_LOGIN,
81
+ env.WEBDAV_PASSWORD,
82
+ ),
83
+ )
84
+ except Exception as e:
85
+ logger.error(e)
86
+ return False
87
+
88
+ if response.status_code in [200, 204]:
89
+ return True
90
+
91
+ logger.error(f"failed to delete: {response.status_code} - {response.text}")
92
+ return False
93
+
94
+ def mkdir(
95
+ self,
96
+ path: str,
97
+ log: bool = True,
98
+ ) -> bool:
99
+ url = f"{env.WEBDAV_HOSTNAME}/"
100
+ for folder in path.split("/"):
101
+ url = f"{url}{folder}/"
102
+
103
+ try:
104
+ response = requests.request(
105
+ "MKCOL",
106
+ url,
107
+ auth=HTTPBasicAuth(
108
+ env.WEBDAV_LOGIN,
109
+ env.WEBDAV_PASSWORD,
110
+ ),
111
+ )
112
+ except Exception as e:
113
+ logger.error(e)
114
+ return False
115
+
116
+ if response.status_code == 405: # Already exists
117
+ continue
118
+
119
+ if response.status_code == 201: # Created
120
+ if log:
121
+ logger.info(
122
+ "{}.mkdir {}".format(
123
+ self.__class__.__name__,
124
+ url.split(env.WEBDAV_HOSTNAME, 1)[1],
125
+ )
126
+ )
127
+ continue
128
+
129
+ logger.error(f"failed to create: {response.status_code} - {response.text}")
130
+ return False
131
+
132
+ return True
133
+
134
+ def download(
135
+ self,
136
+ object_name: str,
137
+ filename: str = "",
138
+ log: bool = True,
139
+ ) -> bool:
140
+ if filename:
141
+ local_path = objects.path_of(
142
+ object_name=object_name,
143
+ filename=filename,
144
+ create=True,
145
+ )
146
+
147
+ if not path.create(file.path(local_path)):
148
+ return False
149
+
150
+ url = f"{env.WEBDAV_HOSTNAME}/{object_name}/{filename}"
151
+
152
+ try:
153
+ response = requests.get(
154
+ url,
155
+ auth=HTTPBasicAuth(
156
+ env.WEBDAV_LOGIN,
157
+ env.WEBDAV_PASSWORD,
158
+ ),
159
+ )
160
+ except Exception as e:
161
+ logger.error(e)
162
+ return False
163
+
164
+ if response.status_code == 404: # object not found
165
+ return True
166
+
167
+ if response.status_code == 200:
168
+ try:
169
+ with open(local_path, "wb") as file_:
170
+ file_.write(response.content)
171
+ except Exception as e:
172
+ logger.error(e)
173
+ return False
174
+
175
+ return super().download(
176
+ object_name=object_name,
177
+ filename=filename,
178
+ log=log,
179
+ )
180
+
181
+ logger.error(f"failed to download: {response.status_code}")
182
+ return False
183
+
184
+ success, list_of_files = self.ls(
185
+ object_name=object_name,
186
+ where="cloud",
187
+ )
188
+ if not success:
189
+ return False
190
+
191
+ for filename_ in tqdm(list_of_files):
192
+ if not self.download(
193
+ object_name=object_name,
194
+ filename=filename_,
195
+ log=log,
196
+ ):
197
+ return False
198
+
199
+ return True
200
+
201
+ def list_raw(
202
+ self,
203
+ suffix: str,
204
+ recursive: bool,
205
+ ) -> Tuple[bool, List[str]]:
206
+ # https://chatgpt.com/c/6824f8d3-d9c0-8005-a7fa-d646f812f4b7
207
+ headers = {
208
+ "Depth": "infinity" if recursive else "1",
209
+ "Content-Type": "application/xml",
210
+ }
211
+
212
+ # Minimal PROPFIND XML body
213
+ data = """<?xml version="1.0"?>
214
+ <d:propfind xmlns:d="DAV:">
215
+ <d:prop><d:displayname/></d:prop>
216
+ </d:propfind>"""
217
+
218
+ try:
219
+ response = requests.request(
220
+ method="PROPFIND",
221
+ url=f"{env.WEBDAV_HOSTNAME}/{suffix}",
222
+ data=data,
223
+ headers=headers,
224
+ auth=HTTPBasicAuth(
225
+ env.WEBDAV_LOGIN,
226
+ env.WEBDAV_PASSWORD,
227
+ ),
228
+ )
229
+ except Exception as e:
230
+ logger.error(e)
231
+ return False, []
232
+
233
+ if response.status_code == 404: # object not found
234
+ return True, []
235
+
236
+ if response.status_code in (207, 207):
237
+ tree = ET.fromstring(response.content)
238
+ ns = {"d": "DAV:"}
239
+ list_of_files = []
240
+ for resp in tree.findall("d:response", ns):
241
+ href = resp.find("d:href", ns).text
242
+ list_of_files.append(href)
243
+
244
+ return True, list_of_files
245
+
246
+ logger.error(f"failed to list: {response.status_code} - {response.text}")
247
+ return False, []
248
+
249
+ def ls(
250
+ self,
251
+ object_name: str,
252
+ where: str = "local",
253
+ ) -> Tuple[bool, List[str]]:
254
+ if where == "cloud":
255
+ success, list_of_files = self.list_raw(
256
+ suffix=f"{object_name}/",
257
+ recursive=True,
258
+ )
259
+
260
+ return success, sorted(
261
+ [
262
+ filename
263
+ for filename in [
264
+ filename.split(f"{env.WEBDAV_LOGIN}/{object_name}/", 1)[1]
265
+ for filename in list_of_files
266
+ if not filename.endswith("/")
267
+ ]
268
+ if filename
269
+ ]
270
+ )
271
+
272
+ return super().ls(
273
+ object_name=object_name,
274
+ where=where,
275
+ )
276
+
277
+ def upload(
278
+ self,
279
+ object_name: str,
280
+ filename: str = "",
281
+ log: bool = True,
282
+ ) -> bool:
283
+ if filename:
284
+ if not self.mkdir(
285
+ path="{}/{}".format(
286
+ object_name,
287
+ file.path(filename),
288
+ ),
289
+ log=log,
290
+ ):
291
+ return False
292
+
293
+ url = f"{env.WEBDAV_HOSTNAME}/{object_name}/{filename}"
294
+
295
+ local_path = objects.path_of(
296
+ object_name=object_name,
297
+ filename=filename,
298
+ )
299
+
300
+ try:
301
+ with open(local_path, "rb") as file_data:
302
+ response = requests.put(
303
+ url,
304
+ data=file_data,
305
+ auth=HTTPBasicAuth(
306
+ env.WEBDAV_LOGIN,
307
+ env.WEBDAV_PASSWORD,
308
+ ),
309
+ )
310
+ except Exception as e:
311
+ logger.error(e)
312
+ return False
313
+
314
+ if response.status_code in [200, 201, 204]:
315
+ return super().upload(
316
+ object_name=object_name,
317
+ filename=filename,
318
+ log=log,
319
+ )
320
+
321
+ logger.error(f"failed to upload: {response.status_code} - {response.text}")
322
+ return False
323
+
324
+ object_path = "{}/".format(objects.object_path(object_name=object_name))
325
+ for filename_ in tqdm(
326
+ sorted(
327
+ glob.glob(
328
+ objects.path_of(
329
+ object_name=object_name,
330
+ filename="**",
331
+ ),
332
+ recursive=True,
333
+ )
334
+ )
335
+ ):
336
+ if not file.exists(filename_):
337
+ continue
338
+
339
+ if not self.upload(
340
+ object_name=object_name,
341
+ filename=filename_.split(object_path, 1)[1],
342
+ log=log,
343
+ ):
344
+ return False
345
+
346
+ return True
@@ -13,7 +13,7 @@ from bluer_objects.logger import logger
13
13
 
14
14
  # tars the objects to avoid 'content-length' - see WebDAVInterface.
15
15
  class WebDAVzipInterface(StorageInterface):
16
- name = "webdavzip"
16
+ name = "webdav-zip"
17
17
 
18
18
  def __init__(self):
19
19
  super().__init__()
@@ -106,24 +106,6 @@ class WebDAVzipInterface(StorageInterface):
106
106
  object_name: str,
107
107
  where: str = "local",
108
108
  ) -> Tuple[bool, List[str]]:
109
- if where == "local":
110
- object_path = objects.object_path(
111
- object_name=object_name,
112
- )
113
-
114
- return True, [
115
- os.path.relpath(filename, start=object_path)
116
- for filename in glob.glob(
117
- os.path.join(
118
- object_path,
119
- "**",
120
- "*",
121
- ),
122
- recursive=True,
123
- )
124
- if os.path.isfile(filename)
125
- ]
126
-
127
109
  if where == "cloud":
128
110
  try:
129
111
  if self.client.check(remote_path=f"{object_name}.zip"):
@@ -134,8 +116,10 @@ class WebDAVzipInterface(StorageInterface):
134
116
 
135
117
  return True, []
136
118
 
137
- logger.error(f"Unknown 'where': {where}")
138
- return False, []
119
+ return super().ls(
120
+ object_name=object_name,
121
+ where=where,
122
+ )
139
123
 
140
124
  def upload(
141
125
  self,
@@ -2,6 +2,7 @@ from typing import Tuple, List
2
2
 
3
3
  from bluer_objects.storage.base import StorageInterface
4
4
  from bluer_objects.storage.WebDAV import WebDAVInterface
5
+ from bluer_objects.storage.WebDAVrequest import WebDAVRequestInterface
5
6
  from bluer_objects.storage.WebDAVzip import WebDAVzipInterface
6
7
  from bluer_objects import env
7
8
  from bluer_objects.logger import logger
@@ -10,6 +11,8 @@ interface = StorageInterface()
10
11
 
11
12
  if env.BLUER_OBJECTS_STORAGE_INTERFACE == WebDAVInterface.name:
12
13
  interface = WebDAVInterface()
14
+ elif env.BLUER_OBJECTS_STORAGE_INTERFACE == WebDAVRequestInterface.name:
15
+ interface = WebDAVRequestInterface()
13
16
  elif env.BLUER_OBJECTS_STORAGE_INTERFACE == WebDAVzipInterface.name:
14
17
  interface = WebDAVzipInterface()
15
18
  else:
@@ -1,5 +1,8 @@
1
+ import os
2
+ import glob
1
3
  from typing import Tuple, List
2
4
 
5
+ from bluer_objects import objects
3
6
  from bluer_objects.logger import logger
4
7
 
5
8
 
@@ -8,7 +11,7 @@ class StorageInterface:
8
11
  self,
9
12
  do_dryrun: bool = True,
10
13
  ) -> bool:
11
- return False
14
+ return True
12
15
 
13
16
  def download(
14
17
  self,
@@ -32,7 +35,32 @@ class StorageInterface:
32
35
  object_name: str,
33
36
  where: str = "local",
34
37
  ) -> Tuple[bool, List[str]]:
35
- return True, []
38
+ if where == "local":
39
+ object_path = objects.object_path(
40
+ object_name=object_name,
41
+ )
42
+
43
+ return True, sorted(
44
+ [
45
+ os.path.relpath(filename, start=object_path)
46
+ for filename in glob.glob(
47
+ os.path.join(
48
+ object_path,
49
+ "**",
50
+ "*",
51
+ ),
52
+ recursive=True,
53
+ )
54
+ if os.path.isfile(filename)
55
+ ]
56
+ )
57
+
58
+ if where == "cloud":
59
+ logger.error("not implemented")
60
+ return False, []
61
+
62
+ logger.error(f"Unknown 'where': {where}")
63
+ return False, []
36
64
 
37
65
  def upload(
38
66
  self,
@@ -2,6 +2,7 @@ from bluer_ai.tests.test_env import test_bluer_ai_env
2
2
 
3
3
  from bluer_objects import env
4
4
  from bluer_objects.storage.WebDAV import WebDAVInterface
5
+ from bluer_objects.storage.WebDAVrequest import WebDAVRequestInterface
5
6
  from bluer_objects.storage.WebDAVzip import WebDAVzipInterface
6
7
 
7
8
 
@@ -14,6 +15,7 @@ def test_bluer_objects_env():
14
15
 
15
16
  assert env.BLUER_OBJECTS_STORAGE_INTERFACE in [
16
17
  WebDAVInterface.name,
18
+ WebDAVRequestInterface.name,
17
19
  WebDAVzipInterface.name,
18
20
  ]
19
21
 
@@ -0,0 +1,46 @@
1
+ import pytest
2
+
3
+ from bluer_options import string
4
+
5
+ from bluer_objects import file, objects
6
+ from bluer_objects.file.load import load_text
7
+ from bluer_objects.file.save import save_text
8
+ from bluer_objects.tests.test_objects import test_object
9
+
10
+
11
+ @pytest.mark.parametrize(
12
+ [
13
+ "filename",
14
+ ],
15
+ [
16
+ ["test.json"],
17
+ ["test.yaml"],
18
+ ["test.yaml"],
19
+ ],
20
+ )
21
+ def test_file_load_save_text(
22
+ test_object,
23
+ filename: str,
24
+ ):
25
+ filename_input = objects.path_of(
26
+ object_name=test_object,
27
+ filename=filename,
28
+ )
29
+ success, text_input = load_text(filename_input)
30
+ assert success
31
+
32
+ filename_test = file.add_suffix(
33
+ filename_input,
34
+ string.random(),
35
+ )
36
+ assert save_text(
37
+ filename_test,
38
+ text_input,
39
+ )
40
+
41
+ success, text_output = load_text(filename_test)
42
+ assert success
43
+
44
+ assert len(text_input) == len(text_output)
45
+ for line_input, line_output in zip(text_input, text_output):
46
+ assert line_input == line_output