Skip to content

Commit 71f3a10

Browse files
Fix optional parameters handling in upload_dir
1 parent 064145b commit 71f3a10

File tree

4 files changed

+67
-8
lines changed

4 files changed

+67
-8
lines changed

cloudinary_cli/modules/upload_dir.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,7 @@ def upload_dir(directory, glob_pattern, include_hidden, optional_parameter, opti
5151
logger.info(f"Uploading directory '{dir_to_upload}'")
5252
parent = dirname(dir_to_upload)
5353

54-
options = {
55-
**{k: v for k, v in optional_parameter},
56-
**{k: parse_option_value(v) for k, v in optional_parameter_parsed},
54+
defaults = {
5755
"resource_type": "auto",
5856
"invalidate": True,
5957
"unique_filename": False,
@@ -62,6 +60,12 @@ def upload_dir(directory, glob_pattern, include_hidden, optional_parameter, opti
6260
"upload_preset": preset
6361
}
6462

63+
options = {
64+
**defaults,
65+
**{k: v for k, v in optional_parameter},
66+
**{k: parse_option_value(v) for k, v in optional_parameter_parsed},
67+
}
68+
6569
uploads = []
6670

6771
for file_path in dir_to_upload.glob(glob_pattern):
@@ -77,7 +81,7 @@ def upload_dir(directory, glob_pattern, include_hidden, optional_parameter, opti
7781
logger.info(style("{} resources uploaded".format(len(items)), fg="green"))
7882

7983
if skipped:
80-
logger.warn("{} items skipped".format(len(skipped)))
84+
logger.warning("{} items skipped".format(len(skipped)))
8185
return False
8286

8387
return True

cloudinary_cli/utils/utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,8 @@ def write_json_list_to_csv(json_list, filename, fields_to_keep=()):
157157

158158

159159
def run_tasks_concurrently(func, tasks, concurrent_workers):
160-
thread_pool = pool.ThreadPool(concurrent_workers)
161-
thread_pool.starmap(func, tasks)
160+
with pool.ThreadPool(concurrent_workers) as thread_pool:
161+
thread_pool.starmap(func, tasks)
162162

163163

164164
def confirm_action(message="Continue? (y/N)"):

test/helper_test.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
22
import random
3+
import re
34
import time
45
from functools import wraps
56
from pathlib import Path
@@ -37,7 +38,45 @@ def api_response_mock():
3738

3839

3940
def uploader_response_mock():
40-
return http_response_mock('{"foo":"bar"}')
41+
return http_response_mock('''{
42+
"public_id": "mocked_file_id.bin",
43+
"resource_type": "raw",
44+
"type": "upload",
45+
"format":"bin",
46+
"foo": "bar"
47+
}''')
48+
49+
50+
def get_request_url(mocker):
51+
return mocker.call_args[0][1]
52+
53+
54+
def get_params(mocker):
55+
"""
56+
Extracts query parameters from mocked urllib3.request `fields` param.
57+
Supports both list and dict values of `fields`. Returns params as dictionary.
58+
Supports two list params formats:
59+
- {"urls[0]": "http://host1", "urls[1]": "http://host2"}
60+
- [("urls[]", "http://host1"), ("urls[]", "http://host2")]
61+
In both cases the result would be {"urls": ["http://host1", "http://host2"]}
62+
"""
63+
64+
args = mocker.call_args[0]
65+
if not args or not args[2]:
66+
return {}
67+
params = {}
68+
reg = re.compile(r'^(.*)\[\d*]$')
69+
fields = args[2].items() if isinstance(args[2], dict) else args[2]
70+
for k, v in fields:
71+
match = reg.match(k)
72+
if match:
73+
name = match.group(1)
74+
if name not in params:
75+
params[name] = []
76+
params[name].append(v)
77+
else:
78+
params[k] = v
79+
return params
4180

4281

4382
def retry_assertion(num_tries=3, delay=3):

test/test_modules/test_cli_upload_dir.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import time
22
import unittest
3+
from unittest.mock import patch
34

45
from click.testing import CliRunner
56

67
from cloudinary_cli.cli import cli
7-
from test.helper_test import unique_suffix, TEST_FILES_DIR, delete_cld_folder_if_exists
8+
from test.helper_test import unique_suffix, TEST_FILES_DIR, delete_cld_folder_if_exists, uploader_response_mock, \
9+
get_request_url, get_params
810

11+
UPLOAD_MOCK_RESPONSE = uploader_response_mock()
912

1013
class TestCLIUploadDir(unittest.TestCase):
1114
runner = CliRunner()
@@ -51,3 +54,16 @@ def test_upload_dir_with_exclude_dir_name_option(self):
5154
self.assertIn("12 resources uploaded", result.output)
5255
self.assertIn("as " + self.CLD_UPLOAD_DIR, result.output)
5356
self.assertNotIn("as " + self.CLD_UPLOAD_DIR + "/test_sync/", result.output)
57+
58+
@patch('urllib3.request.RequestMethods.request')
59+
def test_upload_dir_override_defaults(self, mocker):
60+
mocker.return_value = UPLOAD_MOCK_RESPONSE
61+
62+
result = self.runner.invoke(cli, ["upload_dir", TEST_FILES_DIR, "-f", self.CLD_UPLOAD_DIR,
63+
"-o", "resource_type", "raw", "-O", "unique_filename", "True"])
64+
65+
self.assertEqual(0, result.exit_code)
66+
self.assertIn("12 resources uploaded", result.output)
67+
68+
self.assertIn("raw/upload", get_request_url(mocker))
69+
self.assertTrue(get_params(mocker)['unique_filename'])

0 commit comments

Comments
 (0)