Skip to content

Commit de99296

Browse files
const-cloudinarylukitsbrian
authored andcommitted
Add support for utility methods
1 parent 3aee9ac commit de99296

File tree

5 files changed

+84
-25
lines changed

5 files changed

+84
-25
lines changed

cloudinary_cli/core/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from cloudinary_cli.core.config import config
55
from cloudinary_cli.core.search import search
66
from cloudinary_cli.core.uploader import uploader
7-
from cloudinary_cli.core.utils import url
7+
from cloudinary_cli.core.utils import url, utils
88
from cloudinary_cli.core.overrides import resolve_command
99

1010
setattr(click.MultiCommand, "resolve_command", resolve_command)
@@ -15,4 +15,5 @@
1515
admin,
1616
uploader,
1717
url,
18+
utils
1819
]

cloudinary_cli/core/overrides.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from click.utils import make_str
33
from cloudinary import api, uploader
44
from cloudinary.uploader import upload as original_upload
5+
from cloudinary.utils import cloudinary_url as original_cloudinary_url
56

67

78
# overrides click.MultiCommand.resolve_command
@@ -37,3 +38,8 @@ def upload(file, **options):
3738
if "resource_type" not in options.keys():
3839
options["resource_type"] = "auto"
3940
return original_upload(file, **options)
41+
42+
43+
# Patch to return only the URL
44+
def cloudinary_url(source, **options):
45+
return original_cloudinary_url(source, **options)[0]

cloudinary_cli/core/utils.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,29 @@
11
from webbrowser import open as open_url
22

33
from click import command, argument, option, Choice, echo
4-
from cloudinary.utils import cloudinary_url
4+
from cloudinary import utils as cld_utils
5+
6+
from cloudinary_cli.core.overrides import cloudinary_url
7+
from cloudinary_cli.utils.api_utils import handle_command
8+
from cloudinary_cli.utils.utils import print_help
9+
10+
cld_utils.cloudinary_url = cloudinary_url
11+
12+
utils_list = ["api_sign_request", "cloudinary_url", "download_archive_url", "download_zip_url",
13+
"download_backedup_asset", "verify_api_response_signature", "verify_notification_signature"]
14+
15+
16+
@command("utils", help="Call Cloudinary utility methods.")
17+
@argument("params", nargs=-1)
18+
@option("-o", "--optional_parameter", multiple=True, nargs=2, help="Pass optional parameters as raw strings.")
19+
@option("-O", "--optional_parameter_parsed", multiple=True, nargs=2,
20+
help="Pass optional parameters as interpreted strings.")
21+
@option("-ls", "--ls", is_flag=True, help="List all available utility methods.")
22+
def utils(params, optional_parameter, optional_parameter_parsed, ls):
23+
if ls or len(params) < 1:
24+
return print_help(cld_utils, allow_list=utils_list)
25+
26+
echo(handle_command(params, optional_parameter, optional_parameter_parsed, cld_utils, "Utils"))
527

628

729
@command("url", help="Generate a Cloudinary URL, which you can optionally open in your browser.")
@@ -20,7 +42,7 @@ def url(public_id, transformation, resource_type, delivery_type, open_in_browser
2042
public_id += ".json"
2143

2244
res = cloudinary_url(public_id, resource_type=resource_type,
23-
raw_transformation=transformation, type=delivery_type, sign_url=sign)[0]
45+
raw_transformation=transformation, type=delivery_type, sign_url=sign)
2446
echo(res)
2547

2648
if open_in_browser:

cloudinary_cli/utils/api_utils.py

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,31 @@ def download_file(remote_file, local_path):
6868
logger.info(style("Downloaded '{}' to '{}'".format(remote_file['relative_path'], local_path), fg="green"))
6969

7070

71+
def handle_command(
72+
params,
73+
optional_parameter,
74+
optional_parameter_parsed,
75+
module,
76+
module_name):
77+
78+
try:
79+
func = module.__dict__[params[0]]
80+
except KeyError:
81+
raise Exception(f"Method {params[0]} does not exist in {module_name.capitalize()}.")
82+
83+
if not callable(func):
84+
raise Exception(f"{params[0]} is not callable.")
85+
86+
args, kwargs = parse_args_kwargs(func, params[1:]) if len(params) > 1 else ([], {})
87+
kwargs = {
88+
**kwargs,
89+
**{k: v for k, v in optional_parameter},
90+
**{k: parse_option_value(v) for k, v in optional_parameter_parsed},
91+
}
92+
93+
return func(*args, **kwargs)
94+
95+
7196
def handle_api_command(
7297
params,
7398
optional_parameter,
@@ -87,20 +112,12 @@ def handle_api_command(
87112
if ls or len(params) < 1:
88113
return print_help(api_instance)
89114

90-
try:
91-
func = api_instance.__dict__[params[0]]
92-
if not callable(func):
93-
raise Exception(f"{func} is not callable")
94-
except Exception:
95-
raise Exception(f"Method {params[0]} does not exist in the {api_name.capitalize()} API.")
96-
97-
args, kwargs = parse_args_kwargs(func, params[1:]) if len(params) > 1 else ([], {})
98-
99-
res = func(*args, **{
100-
**kwargs,
101-
**{k: v for k, v in optional_parameter},
102-
**{k: parse_option_value(v) for k, v in optional_parameter_parsed},
103-
})
115+
res = handle_command(
116+
params,
117+
optional_parameter,
118+
optional_parameter_parsed,
119+
api_instance,
120+
api_name)
104121

105122
print_json(res)
106123

cloudinary_cli/utils/utils.py

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env python3
2-
2+
import builtins
33
import json
44
import os
55
from csv import DictWriter
@@ -13,7 +13,7 @@
1313

1414
from cloudinary_cli.defaults import logger, TEMPLATE_FOLDER
1515

16-
not_callable = ['is_appengine_sandbox', 'call_tags_api', 'call_context_api', 'call_cacheable_api', 'call_api', 'text']
16+
not_callable = ('is_appengine_sandbox', 'call_tags_api', 'call_context_api', 'call_cacheable_api', 'call_api', 'text')
1717

1818
BLOCK_SIZE = 65536
1919

@@ -29,14 +29,27 @@ def etag(fi):
2929
return file_hash.hexdigest()
3030

3131

32-
def get_help_str(api):
33-
funcs = list(filter(lambda x: callable(api.__dict__[x]) and x[0].islower() and x not in not_callable,
34-
api.__dict__.keys()))
35-
return '\n'.join(["{0:25}({1})".format(x, ", ".join(list(signature(api.__dict__[x]).parameters))) for x in funcs])
32+
def is_builtin_class_instance(obj):
33+
return type(obj).__name__ in dir(builtins)
34+
35+
36+
def get_help_str(module, block_list=(), allow_list=()):
37+
funcs = list(filter(
38+
lambda f:
39+
callable(module.__dict__[f])
40+
and not is_builtin_class_instance(module.__dict__[f])
41+
and f[0].islower()
42+
and (f not in block_list and block_list)
43+
and (f in allow_list or not allow_list),
44+
module.__dict__.keys()))
45+
46+
template = "{0:" + str(len(max(funcs, key=len)) + 1) + "}({1})" # Gets the maximal length of the functions' names
47+
48+
return '\n'.join([template.format(f, ", ".join(list(signature(module.__dict__[f]).parameters))) for f in funcs])
3649

3750

38-
def print_help(api):
39-
logger.info(get_help_str(api))
51+
def print_help(api, block_list=not_callable, allow_list=()):
52+
logger.info(get_help_str(api, block_list=block_list, allow_list=allow_list))
4053

4154

4255
def log_exception(e, message=None):

0 commit comments

Comments
 (0)