Skip to content

Commit f92947f

Browse files
authored
Feature/required args (#66)
1 parent 8394813 commit f92947f

File tree

11 files changed

+147
-68
lines changed

11 files changed

+147
-68
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ how a consumer would use the library (e.g. adding unit tests, updating documenta
1010

1111
## Unreleased
1212

13+
### Changed
14+
15+
- `code42 profile create` now uses required `--name`, `--server` and `--username` flags instead of positional arguments.
16+
17+
- `code42 high-risk-employee add-risk-tags` now uses required `--username` and `--tag` flags instead of positional arguments.
18+
19+
- `code42 high-risk-employee remove-risk-tags` now uses required `--username` and `--tag` flags instead of positional arguments.
20+
1321
### Added
1422

1523
- `code42 alerts`:

src/code42cli/args.py

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def add_short_option_name(self, short_name):
3838
def as_multi_val_param(self, nargs=u"+"):
3939
self._settings[u"nargs"] = nargs
4040

41-
def set_required(self, required=False):
41+
def set_required(self, required):
4242
self._settings[u"required"] = required
4343

4444

@@ -61,51 +61,51 @@ def get_auto_arg_configs(handler):
6161
"""Looks at the parameter names of `handler` and builds an `ArgConfigCollection` containing
6262
`argparse` parameters based on them."""
6363
arg_configs = ArgConfigCollection()
64+
excluded_args = [SDK_ARG_NAME, u"profile", u"args", u"kwargs", u"self"]
6465
if callable(handler):
65-
# get the number of positional and keyword args
6666
argspec = inspect.getargspec(handler)
67-
num_args = len(argspec.args)
68-
num_kw_args = len(argspec.defaults) if argspec.defaults else 0
69-
70-
for arg_position, key in enumerate(argspec.args):
71-
# do not create cli parameters for arguments named "sdk", "args", or "kwargs"
72-
if not key in [SDK_ARG_NAME, u"args", u"kwargs", u"self"]:
73-
arg_config = _create_auto_args_config(
74-
arg_position, key, argspec, num_args, num_kw_args
75-
)
76-
_set_smart_defaults(arg_config)
77-
arg_configs.append(key, arg_config)
67+
filtered_argspec = {
68+
key: position for position, key in enumerate(argspec.args) if key not in excluded_args
69+
}
70+
num_optional_args = len(argspec.defaults) if argspec.defaults else 0
71+
num_positional_args = len(argspec.args) - num_optional_args
72+
num_required_cli_args = len(filtered_argspec) - num_optional_args
73+
74+
for key in filtered_argspec:
75+
arg_config = _create_auto_args_config(
76+
key, filtered_argspec[key], num_positional_args, num_required_cli_args, argspec
77+
)
78+
_set_smart_defaults(arg_config)
79+
arg_configs.append(key, arg_config)
7880

7981
if SDK_ARG_NAME in argspec.args:
8082
_build_sdk_arg_configs(arg_configs)
8183

8284
return arg_configs
8385

8486

85-
def _create_auto_args_config(arg_position, key, argspec, num_args, num_kw_args):
87+
def _create_auto_args_config(key, position, num_positional_args, num_required_cli_args, argspec):
8688
default = None
89+
required = None
8790
param_name = key.replace(u"_", u"-")
88-
difference = num_args - num_kw_args
89-
last_positional_arg_idx = difference - 1
91+
last_positional_arg_idx = num_positional_args - 1
92+
option_names = [u"--{}".format(param_name)]
9093
# positional arguments will come first, so if the arg position
9194
# is greater than the index of the last positional arg, it's a kwarg.
92-
if arg_position > last_positional_arg_idx:
95+
if position > last_positional_arg_idx:
9396
# this is a keyword arg, treat it as an optional cli arg.
94-
default_value = argspec.defaults[arg_position - difference]
95-
option_names = [u"--{}".format(param_name)]
97+
default_value = argspec.defaults[position - num_positional_args]
9698
default = default_value
97-
else:
99+
elif num_required_cli_args > 1:
98100
# this is a positional arg, treat it as a required cli arg.
101+
required = True
102+
else:
99103
option_names = [param_name]
100-
return ArgConfig(*option_names, default=default)
104+
return ArgConfig(*option_names, default=default, required=required)
101105

102106

103107
def _set_smart_defaults(arg_config):
104108
default = arg_config.settings.get(u"default")
105-
# make a parameter allow lists as input if its default value is a list,
106-
# e.g. --my-param one two three four
107-
nargs = u"+" if type(default) == list else None
108-
arg_config.settings[u"nargs"] = nargs
109109
# make the param not require a value (e.g. --enable) if the default value of
110110
# the param is a bool.
111111
if type(default) == bool:

src/code42cli/cmds/alerts/rules/commands.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,22 @@
66
get_rules,
77
add_bulk_users,
88
remove_bulk_users,
9-
show_rules,
9+
show_rule,
1010
)
1111

1212

1313
def _customize_add_arguments(argument_collection):
1414
rule_id = argument_collection.arg_configs[u"rule_id"]
1515
rule_id.set_help(u"Observer ID of the rule to be updated. Required.")
16-
rule_id.set_required(True)
1716
username = argument_collection.arg_configs[u"username"]
1817
username.set_help(u"The username of the user to add to the alert rule. Required.")
19-
username.set_required(True)
2018

2119

2220
def _customize_remove_arguments(argument_collection):
2321
rule_id = argument_collection.arg_configs[u"rule_id"]
2422
rule_id.set_help(u"Observer ID of the rule to be updated.")
25-
rule_id.set_required(True)
2623
username = argument_collection.arg_configs[u"username"]
2724
username.set_help(u"The username of the user to remove from the alert rule.")
28-
username.set_required(True)
2925

3026

3127
def _customize_list_arguments(argument_collection):
@@ -131,7 +127,7 @@ def load_subcommands():
131127
u"show",
132128
u"Fetch configured alert-rules against the rule ID.",
133129
u"{} show <rule-id>".format(usage_prefix),
134-
handler=show_rules,
130+
handler=show_rule,
135131
arg_customizer=_customize_list_arguments,
136132
)
137133

src/code42cli/cmds/alerts/rules/user_rule.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@
1717
}
1818

1919

20-
def add_user(sdk, profile, rule_id=None, username=None):
20+
def add_user(sdk, profile, rule_id, username):
2121
user_id = get_user_id(sdk, username)
2222
sdk.alerts.rules.add_user(rule_id, user_id)
2323

2424

25-
def remove_user(sdk, profile, rule_id=None, username=None):
25+
def remove_user(sdk, profile, rule_id, username):
2626
if username:
2727
user_id = get_user_id(sdk, username)
2828
sdk.alerts.rules.remove_user(rule_id, user_id)
@@ -58,7 +58,7 @@ def remove_bulk_users(sdk, profile, file_name):
5858
)
5959

6060

61-
def show_rules(sdk, profile, rule_id):
61+
def show_rule(sdk, profile, rule_id):
6262
selected_rule = _get_rules_metadata(sdk, rule_id)
6363
rule_detail = None
6464
if len(selected_rule):

src/code42cli/cmds/detectionlists/high_risk_employee.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@ def load_subcommands():
2424
Command(
2525
u"add-risk-tags",
2626
u"Associates risk tags with a user.",
27+
u"code42 high-risk-employee add-risk-tags --username <username> --tag <risk-tags>",
2728
handler=add_risk_tags,
2829
arg_customizer=_load_risk_tag_mgmt_descriptions,
2930
),
3031
Command(
3132
u"remove-risk-tags",
3233
u"Disassociates risk tags from a user.",
34+
u"code42 high-risk-employee remove-risk-tags --username <username> --tag <risk-tags>",
3335
handler=remove_risk_tags,
3436
arg_customizer=_load_risk_tag_mgmt_descriptions,
3537
),
@@ -44,14 +46,14 @@ def _create_handlers():
4446
)
4547

4648

47-
def add_risk_tags(sdk, profile, username, risk_tag):
48-
risk_tag = _handle_list_args(risk_tag)
49+
def add_risk_tags(sdk, profile, username, tag):
50+
risk_tag = _handle_list_args(tag)
4951
user_id = get_user_id(sdk, username)
5052
try_add_risk_tags(sdk, user_id, risk_tag)
5153

5254

53-
def remove_risk_tags(sdk, profile, username, risk_tag):
54-
risk_tag = _handle_list_args(risk_tag)
55+
def remove_risk_tags(sdk, profile, username, tag):
56+
risk_tag = _handle_list_args(tag)
5557
user_id = get_user_id(sdk, username)
5658
try_remove_risk_tags(sdk, user_id, risk_tag)
5759

@@ -92,7 +94,10 @@ def remove_high_risk_employee(sdk, profile, username):
9294

9395

9496
def _load_risk_tag_description(argument_collection):
95-
risk_tag = argument_collection.arg_configs[DetectionListUserKeys.RISK_TAG]
97+
risk_tag = (
98+
argument_collection.arg_configs.get(DetectionListUserKeys.RISK_TAG)
99+
or argument_collection.arg_configs[u"tag"]
100+
)
96101
risk_tag.as_multi_val_param()
97102
tags = u", ".join(list(RiskTags()))
98103
risk_tag.set_help(

src/code42cli/cmds/profile.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ def load_subcommands():
4747
create = Command(
4848
u"create",
4949
u"Create profile settings. The first profile created will be the default.",
50-
u"{} {}".format(usage_prefix, u"create <profile-name> <server-address> <username>"),
50+
u"{} {}".format(
51+
usage_prefix,
52+
u"create --name <profile-name> --server <server-address> --username <username>",
53+
),
5154
handler=create_profile,
5255
arg_customizer=_load_profile_create_descriptions,
5356
)
@@ -90,10 +93,10 @@ def show_profile(name=None):
9093
logger.print_info(u"")
9194

9295

93-
def create_profile(profile, server, username, disable_ssl_errors=False):
94-
cliprofile.create_profile(profile, server, username, disable_ssl_errors)
95-
_prompt_for_allow_password_set(profile)
96-
get_main_cli_logger().print_info(u"Successfully created profile '{}'.".format(profile))
96+
def create_profile(name, server, username, disable_ssl_errors=False):
97+
cliprofile.create_profile(name, server, username, disable_ssl_errors)
98+
_prompt_for_allow_password_set(name)
99+
get_main_cli_logger().print_info(u"Successfully created profile '{}'.".format(name))
97100

98101

99102
def update_profile(name=None, server=None, username=None, disable_ssl_errors=None):
@@ -172,7 +175,7 @@ def _load_optional_profile_description(argument_collection):
172175

173176

174177
def _load_profile_create_descriptions(argument_collection):
175-
profile = argument_collection.arg_configs[PROFILE_ARG_NAME]
178+
profile = argument_collection.arg_configs[u"name"]
176179
profile.set_help(PROFILE_HELP)
177180
_load_profile_settings_descriptions(argument_collection)
178181

src/code42cli/parser.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,9 @@ def error(self, message):
4646

4747
def _load_argparse_config(self, command, command_parser):
4848
arg_configs = command.get_arg_configs()
49+
required_group = command_parser.add_argument_group(u"required arguments")
4950
for arg in arg_configs:
50-
_add_argument(command_parser, arg_configs[arg].settings)
51+
_add_argument(command_parser, arg_configs[arg].settings, required_group)
5152

5253
def _get_parser(self, command, path_parts):
5354
usage = command.usage or SUPPRESS
@@ -84,10 +85,12 @@ def _get_parent_subparser(path_parts, part, subparsers):
8485
return parent_subparser
8586

8687

87-
def _add_argument(parser, arg_settings):
88+
def _add_argument(parser, arg_settings, required_group):
8889
# register the settings of an ArgConfig object to an argparse parser
8990
options_list = arg_settings.pop(u"options_list")
9091
arg_settings = {key: arg_settings[key] for key in arg_settings if arg_settings[key] is not None}
92+
if arg_settings.get(u"required"):
93+
parser = required_group
9194
parser.add_argument(*options_list, **arg_settings)
9295

9396

tests/cmds/alerts/rules/test_user_rule.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import pytest
22

3-
from code42cli.cmds.alerts.rules.user_rule import add_user, remove_user, get_rules, show_rules
3+
from code42cli.cmds.alerts.rules.user_rule import add_user, remove_user, get_rules, show_rule
44

55
TEST_RULE_ID = u"rule-id"
66
TEST_USER_ID = u"test-user-id"
@@ -30,28 +30,26 @@ def test_remove_user_removes_user_list_from_alert_rules(alert_rules_sdk, profile
3030
alert_rules_sdk.users.get_by_username.return_value = {u"users": [{u"userUid": TEST_USER_ID}]}
3131
remove_user(alert_rules_sdk, profile, TEST_RULE_ID, TEST_USERNAME)
3232
alert_rules_sdk.alerts.rules.remove_user.assert_called_once_with(TEST_RULE_ID, TEST_USER_ID)
33-
remove_user(alert_rules_sdk, profile, TEST_RULE_ID)
34-
alert_rules_sdk.alerts.rules.remove_all_users.assert_called_once_with(TEST_RULE_ID)
3533

3634

3735
def test_get_rules_gets_alert_rules(alert_rules_sdk, profile):
3836
get_rules(alert_rules_sdk, profile)
3937
assert alert_rules_sdk.alerts.rules.get_all.call_count == 1
4038

4139

42-
def test_show_rules_calls_correct_rule_property(alert_rules_sdk, profile):
40+
def test_show_rule_calls_correct_rule_property(alert_rules_sdk, profile):
4341
alert_rules_sdk.alerts.rules.get_all.return_value = TEST_GET_ALL_RESPONSE_EXFILTRATION
44-
show_rules(alert_rules_sdk, profile, TEST_RULE_ID)
42+
show_rule(alert_rules_sdk, profile, TEST_RULE_ID)
4543
alert_rules_sdk.alerts.rules.exfiltration.get.assert_called_once_with(TEST_RULE_ID)
4644

4745

48-
def test_show_rules_calls_correct_rule_property_cloud_share(alert_rules_sdk, profile):
46+
def test_show_rule_calls_correct_rule_property_cloud_share(alert_rules_sdk, profile):
4947
alert_rules_sdk.alerts.rules.get_all.return_value = TEST_GET_ALL_RESPONSE_CLOUD_SHARE
50-
show_rules(alert_rules_sdk, profile, TEST_RULE_ID)
48+
show_rule(alert_rules_sdk, profile, TEST_RULE_ID)
5149
alert_rules_sdk.alerts.rules.cloudshare.get.assert_called_once_with(TEST_RULE_ID)
5250

5351

54-
def test_show_rules_calls_correct_rule_property_file_type_mismatch(alert_rules_sdk, profile):
52+
def test_show_rule_calls_correct_rule_property_file_type_mismatch(alert_rules_sdk, profile):
5553
alert_rules_sdk.alerts.rules.get_all.return_value = TEST_GET_ALL_RESPONSE_FILE_TYPE_MISMATCH
56-
show_rules(alert_rules_sdk, profile, TEST_RULE_ID)
54+
show_rule(alert_rules_sdk, profile, TEST_RULE_ID)
5755
alert_rules_sdk.alerts.rules.filetypemismatch.get.assert_called_once_with(TEST_RULE_ID)

tests/conftest.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,14 @@ def func_keyword_args(one=None, two=None, three=None, default="testdefault", nar
131131
pass
132132

133133

134+
def func_single_positional_arg(one):
135+
pass
136+
137+
138+
def func_single_positional_arg_many_optional_args(one, two=None, three=None, four=None):
139+
pass
140+
141+
134142
def func_positional_args(one, two, three):
135143
pass
136144

@@ -143,6 +151,12 @@ def func_with_sdk(sdk, one, two, three=None, four=None):
143151
pass
144152

145153

154+
def func_single_positional_arg_with_sdk_and_profile(
155+
sdk, profile, one, two=None, three=None, four=None
156+
):
157+
pass
158+
159+
146160
def func_with_args(args):
147161
pass
148162

0 commit comments

Comments
 (0)