cloudinary-cli 1.10.1__tar.gz → 1.10.3__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 (66) hide show
  1. {cloudinary-cli-1.10.1/cloudinary_cli.egg-info → cloudinary_cli-1.10.3}/PKG-INFO +1 -1
  2. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/core/utils.py +5 -1
  3. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/modules/sync.py +39 -10
  4. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/utils/api_utils.py +5 -3
  5. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/utils/file_utils.py +2 -0
  6. cloudinary_cli-1.10.3/cloudinary_cli/version.py +1 -0
  7. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3/cloudinary_cli.egg-info}/PKG-INFO +1 -1
  8. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/test/test_modules/test_cli_sync.py +8 -1
  9. cloudinary-cli-1.10.1/cloudinary_cli/version.py +0 -1
  10. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/LICENSE +0 -0
  11. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/MANIFEST.in +0 -0
  12. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/README.md +0 -0
  13. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/__init__.py +0 -0
  14. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/cli.py +0 -0
  15. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/cli_group.py +0 -0
  16. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/core/__init__.py +0 -0
  17. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/core/admin.py +0 -0
  18. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/core/config.py +0 -0
  19. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/core/overrides.py +0 -0
  20. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/core/provisioning.py +0 -0
  21. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/core/search.py +0 -0
  22. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/core/uploader.py +0 -0
  23. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/defaults.py +0 -0
  24. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/modules/__init__.py +0 -0
  25. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/modules/make.py +0 -0
  26. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/modules/migrate.py +0 -0
  27. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/modules/regen_derived.py +0 -0
  28. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/modules/upload_dir.py +0 -0
  29. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/samples/__init__.py +0 -0
  30. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/templates/html/media_library_widget +0 -0
  31. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/templates/html/product_gallery +0 -0
  32. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/templates/html/upload_widget +0 -0
  33. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/templates/html/video_player +0 -0
  34. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/templates/node/upload +0 -0
  35. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/templates/python/base +0 -0
  36. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/templates/python/explicit +0 -0
  37. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/templates/python/find_all_empty_folders +0 -0
  38. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/templates/python/upload +0 -0
  39. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/templates/ruby/upload +0 -0
  40. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/utils/__init__.py +0 -0
  41. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/utils/config_utils.py +0 -0
  42. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/utils/json_utils.py +0 -0
  43. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli/utils/utils.py +0 -0
  44. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli.egg-info/SOURCES.txt +0 -0
  45. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli.egg-info/dependency_links.txt +0 -0
  46. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli.egg-info/entry_points.txt +0 -0
  47. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli.egg-info/not-zip-safe +0 -0
  48. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli.egg-info/requires.txt +0 -0
  49. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/cloudinary_cli.egg-info/top_level.txt +0 -0
  50. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/requirements.txt +0 -0
  51. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/setup.cfg +0 -0
  52. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/setup.py +0 -0
  53. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/test/__init__.py +0 -0
  54. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/test/helper_test.py +0 -0
  55. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/test/test_cli.py +0 -0
  56. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/test/test_cli_api.py +0 -0
  57. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/test/test_cli_config.py +0 -0
  58. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/test/test_cli_samples.py +0 -0
  59. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/test/test_cli_search_api.py +0 -0
  60. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/test/test_cli_url.py +0 -0
  61. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/test/test_cli_utils.py +0 -0
  62. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/test/test_file_utils.py +0 -0
  63. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/test/test_modules/__init__.py +0 -0
  64. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/test/test_modules/test_cli_make.py +0 -0
  65. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/test/test_modules/test_cli_upload_dir.py +0 -0
  66. {cloudinary-cli-1.10.1 → cloudinary_cli-1.10.3}/test/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cloudinary-cli
3
- Version: 1.10.1
3
+ Version: 1.10.3
4
4
  Summary: A command line interface for Cloudinary with full API support
5
5
  Home-page: https://github.com/cloudinary/cloudinary-cli
6
6
  Author: Cloudinary, Brian Luk
@@ -36,7 +36,11 @@ def utils(params, optional_parameter, optional_parameter_parsed, ls):
36
36
  @argument("transformation", default="")
37
37
  @option("-rt", "--resource_type", default="image", type=Choice(['image', 'video', 'raw']), help="The asset type")
38
38
  @option("-t", "--type", "delivery_type", default="upload",
39
- type=Choice(['upload', 'private', 'authenticated', 'fetch', 'list', 'url2png']),
39
+ type=Choice([
40
+ 'upload', 'private', 'public', 'authenticated', 'fetch', 'list', 'url2png',
41
+ 'sprite', 'text', 'multi', 'facebook', 'twitter', 'twitter_name', 'gravatar',
42
+ 'youtube', 'hulu', 'vimeo', 'animoto', 'worldstarhiphop', 'dailymotion'
43
+ ]),
40
44
  help="The delivery type.")
41
45
  @option("-o", "--open", 'open_in_browser', is_flag=True, help="Generate the derived asset and open it in your browser.")
42
46
  @option("-s", "--sign", is_flag=True, help="Generate a signed URL.", default=False)
@@ -1,4 +1,5 @@
1
1
  import logging
2
+ import os.path
2
3
  import re
3
4
  from collections import Counter
4
5
  from itertools import groupby
@@ -45,10 +46,6 @@ def sync(local_folder, cloudinary_folder, push, pull, include_hidden, concurrent
45
46
  if push == pull:
46
47
  raise UsageError("Please use either the '--push' OR '--pull' options")
47
48
 
48
- if pull and not cld_folder_exists(cloudinary_folder):
49
- logger.error(f"Cloudinary folder '{cloudinary_folder}' does not exist. Aborting...")
50
- return False
51
-
52
49
  sync_dir = SyncDir(local_folder, cloudinary_folder, include_hidden, concurrent_workers, force, keep_unique,
53
50
  deletion_batch_size, folder_mode, optional_parameter, optional_parameter_parsed)
54
51
 
@@ -58,7 +55,8 @@ def sync(local_folder, cloudinary_folder, push, pull, include_hidden, concurrent
58
55
  elif pull:
59
56
  result = sync_dir.pull()
60
57
 
61
- logger.info("Done!")
58
+ if result:
59
+ logger.info("Done!")
62
60
 
63
61
  return result
64
62
 
@@ -84,12 +82,32 @@ class SyncDir:
84
82
 
85
83
  self.verbose = logger.getEffectiveLevel() < logging.INFO
86
84
 
87
- self.local_files = walk_dir(path.abspath(self.local_dir), include_hidden)
88
- logger.info(f"Found {len(self.local_files)} items in local folder '{local_dir}'")
85
+ self.local_files = {}
86
+ self.local_folder_exists = os.path.isdir(path.abspath(self.local_dir))
87
+ if not self.local_folder_exists:
88
+ logger.info(f"Local folder '{self.local_dir}' does not exist.")
89
+ else:
90
+ self.local_files = walk_dir(path.abspath(self.local_dir), include_hidden)
91
+ if len(self.local_files):
92
+ logger.info(f"Found {len(self.local_files)} items in local folder '{self.local_dir}'")
93
+ else:
94
+ logger.info(f"Local folder '{self.local_dir}' is empty.")
95
+
96
+ raw_remote_files = {}
97
+ self.cld_folder_exists = cld_folder_exists(self.remote_dir)
98
+ if not self.cld_folder_exists:
99
+ logger.info(f"Cloudinary folder '{self.user_friendly_remote_dir}' does not exist "
100
+ f"({self.folder_mode} folder mode).")
101
+ else:
102
+ raw_remote_files = query_cld_folder(self.remote_dir, self.folder_mode)
103
+ if len(raw_remote_files):
104
+ logger.info(
105
+ f"Found {len(raw_remote_files)} items in Cloudinary folder '{self.user_friendly_remote_dir}' "
106
+ f"({self.folder_mode} folder mode).")
107
+ else:
108
+ logger.info(f"Cloudinary folder '{self.user_friendly_remote_dir}' is empty. "
109
+ f"({self.folder_mode} folder mode)")
89
110
 
90
- raw_remote_files = query_cld_folder(self.remote_dir, self.folder_mode)
91
- logger.info(f"Found {len(raw_remote_files)} items in Cloudinary folder '{self.user_friendly_remote_dir}' "
92
- f"({self.folder_mode} folder mode)")
93
111
  self.remote_files = self._normalize_remote_file_names(raw_remote_files, self.local_files)
94
112
  self.remote_duplicate_names = duplicate_values(self.remote_files, "normalized_path", "asset_id")
95
113
  self._print_duplicate_file_names()
@@ -137,6 +155,11 @@ class SyncDir:
137
155
  """
138
156
  Pushes changes from the local folder to the Cloudinary folder.
139
157
  """
158
+
159
+ if not self.local_folder_exists:
160
+ logger.error(f"Cannot push a non-existent local folder '{self.local_dir}'. Aborting...")
161
+ return False
162
+
140
163
  if not self._handle_unique_remote_files():
141
164
  logger.info("Aborting...")
142
165
  return False
@@ -176,6 +199,12 @@ class SyncDir:
176
199
  """
177
200
  Pulls changes from the Cloudinary folder to the local folder.
178
201
  """
202
+
203
+ if not self.cld_folder_exists:
204
+ logger.error(f"Cannot pull from a non-existent Cloudinary folder '{self.user_friendly_remote_dir}' "
205
+ f"({self.folder_mode} folder mode). Aborting...")
206
+ return False
207
+
179
208
  download_results = {}
180
209
  download_errors = {}
181
210
  if not self._handle_unique_local_files():
@@ -59,21 +59,23 @@ def query_cld_folder(folder, folder_mode):
59
59
 
60
60
  return files
61
61
 
62
+
62
63
  def cld_folder_exists(folder):
63
64
  folder = folder.strip('/') # omit redundant leading slash and duplicate trailing slashes in query
64
65
 
65
66
  if not folder:
66
- return True # root folder
67
+ return True # root folder
67
68
 
68
- res = SearchFolders().expression(f"name=\"{folder}\"").execute()
69
+ res = SearchFolders().expression(f"path=\"{folder}\"").execute()
69
70
 
70
71
  return res.get("total_count", 0) > 0
71
72
 
73
+
72
74
  def _display_path(asset):
73
75
  if asset.get("display_name") is None:
74
76
  return ""
75
77
 
76
- return "/".join([asset.get("asset_folder", ""), ".".join([asset["display_name"], asset["format"]])])
78
+ return "/".join([asset.get("asset_folder", ""), ".".join(filter(None, [asset["display_name"], asset.get("format", None)]))])
77
79
 
78
80
 
79
81
  def _relative_display_path(asset, folder):
@@ -129,6 +129,7 @@ def normalize_file_extension(filename: str) -> str:
129
129
 
130
130
  return ".".join([p for p in [filename, extension_alias] if p])
131
131
 
132
+
132
133
  def populate_duplicate_name(filename, index=0):
133
134
  """
134
135
  Adds index to the filename in order to avoid duplicates.
@@ -143,6 +144,7 @@ def populate_duplicate_name(filename, index=0):
143
144
 
144
145
  return ".".join([p for p in [filename, extension[1:]] if p])
145
146
 
147
+
146
148
  def posix_rel_path(end, start) -> str:
147
149
  """
148
150
  Returns a relative path in posix style on any system.
@@ -0,0 +1 @@
1
+ __version__ = "1.10.3"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cloudinary-cli
3
- Version: 1.10.1
3
+ Version: 1.10.3
4
4
  Summary: A command line interface for Cloudinary with full API support
5
5
  Home-page: https://github.com/cloudinary/cloudinary-cli
6
6
  Author: Cloudinary, Brian Luk
@@ -44,6 +44,13 @@ class TestCLISync(unittest.TestCase):
44
44
  self.assertIn("Synced | 12", result.output)
45
45
  self.assertIn("Done!", result.output)
46
46
 
47
+ def test_cli_sync_push_non_existing_folder(self):
48
+ non_existing_dir = self.LOCAL_SYNC_PULL_DIR + "non_existing"
49
+ result = self.runner.invoke(cli, ['sync', '--push', non_existing_dir, self.CLD_SYNC_DIR])
50
+
51
+ self.assertIn(f"Cannot push a non-existent local folder '{non_existing_dir}'", result.output)
52
+ self.assertIn("Aborting...", result.output)
53
+
47
54
  @retry_assertion
48
55
  def test_cli_sync_push_twice(self):
49
56
  self._upload_sync_files(TEST_FILES_DIR)
@@ -92,7 +99,7 @@ class TestCLISync(unittest.TestCase):
92
99
  non_existing_dir = self.CLD_SYNC_DIR + "non_existing"
93
100
  result = self.runner.invoke(cli, ['sync', '--pull', self.LOCAL_SYNC_PULL_DIR, non_existing_dir])
94
101
 
95
- self.assertIn(f"error: Cloudinary folder '{non_existing_dir}' does not exist.", result.output)
102
+ self.assertIn(f"Cannot pull from a non-existent Cloudinary folder '{non_existing_dir}'", result.output)
96
103
  self.assertIn("Aborting...", result.output)
97
104
 
98
105
  @retry_assertion
@@ -1 +0,0 @@
1
- __version__ = "1.10.1"
File without changes