Skip to content

Commit

Permalink
Move cli-help to config class, default is in print utils. Checks the …
Browse files Browse the repository at this point in the history
…return type of allowed_cli_args
  • Loading branch information
OlofHarrysson committed Dec 23, 2020
1 parent 8bcc8d6 commit 23a0d40
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 44 deletions.
11 changes: 3 additions & 8 deletions anyfig/anyfig_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,8 @@ def init_config(default_config, cli_args=None):
fields.validate_fields(config)

# Print config help
if 'help' in cli_args:
config_classes = list(figutils.get_config_classes())
print(
f"Available config classes {config_classes}. Set config with --config=OtherConfigClass\n",
f"\nCurrent config is '{config_str}'. The available input arguments are")

print(config.comments_string())
if 'help' in cli_args or 'h' in cli_args:
print(config.cli_help())
sys.exit(0)

# Overwrite parameters via optional input flags
Expand Down Expand Up @@ -118,7 +113,7 @@ def overwrite(main_config_obj, args):
assert hasattr(config_obj, key_part), err_msg

# Check if the config allows the argument
figutils.allowed_input_argument(config_obj, key_part, argument_key)
figutils.check_allowed_input_argument(config_obj, key_part, argument_key)

# Check if the outer attributes are config classes
if key_idx < len(outer_keys):
Expand Down
5 changes: 2 additions & 3 deletions anyfig/config_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@ def post_init(self):
''' A function that is called after overwriting from command line input '''
pass

def comments_string(self):
''' Returns string for config class's attributes and comments '''
return print_utils.comments_string(self)
def cli_help(self):
return print_utils.cli_help(self)

def frozen(self, freeze=True):
''' Freeze/unfreeze config '''
Expand Down
4 changes: 2 additions & 2 deletions anyfig/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ def validate_fields(config):
for key, val in vars(config).items():
if type(val) is InterfaceField: # Don't check InputField or ConstantField
err_msg = (
f"Missing value for the 'anyfig.field' named '{key}' in config '{type(config).__name__}'. "
"Set a value or use 'anyfig.cli_input' for input arguments without default values"
f"Missing value for '{key}' in config '{type(config).__name__}'. "
"Set a value or change the type to 'anyfig.cli_input' to allow input arguments without default values"
)
assert hasattr(val, 'value'), err_msg

Expand Down
26 changes: 18 additions & 8 deletions anyfig/figutils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import inspect
import dill

from pathlib import Path
from collections.abc import Iterable

import dill

registered_config_classes = {}
global_configs = {}
Expand Down Expand Up @@ -119,21 +120,30 @@ def find_arguments(callable_):
return list(parameters), required_args


def allowed_input_argument(config_obj, name, deep_name):
def check_allowed_input_argument(config_obj, name, deep_name):
''' Raises error if the input argument isn't marked as "allowed" '''
allowed_args = check_allowed_cli_args(config_obj)
allowed_args = get_allowed_cli_args(config_obj)
if name not in allowed_args:
err_msg = f"Input argument '{deep_name}' is not allowed to be overwritten. See --help for more info"
raise ValueError(err_msg)


def check_allowed_cli_args(config_obj):
def get_allowed_cli_args(config_obj):
''' Returns the attribute names that can be be overwritten from command line input.
Raises AttributeError if an attribute doesn't exist '''
Raises AttributeError if an attribute doesn't exist '''
allowed_items = config_obj.allowed_cli_args()
attr = config_obj.get_parameters()
if allowed_items is None:
allowed_items = []
if isinstance(allowed_items, str):
allowed_items = [allowed_items]
err_msg = (
f"Expected return type 'String, None or Iterable' for {type(config_obj).__name__}'s allowed_cli_args method, "
f"was {allowed_items} with type {type(allowed_items)}")
assert isinstance(allowed_items, Iterable), err_msg

attributes = config_obj.get_parameters()
for item in allowed_items:
if item not in attr:
if item not in attributes:
err_msg = (
f"'{type(config_obj).__name__}' has no attribute '{item}' and should not be marked as an allowed command line "
"input argument")
Expand Down
21 changes: 17 additions & 4 deletions anyfig/print_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
from .fields import InputField, InterfaceField


def comments_string(config_obj):
''' Returns a "help" string for the config object that contain attributes and any matching comments '''
def cli_help(config_obj):
''' Returns string for config's cli-arguments with corresponding comments '''
comments = extract_config_obj_comments(config_obj)

indent_width = 4 # In spaces
Expand Down Expand Up @@ -47,7 +47,20 @@ def comments_string(config_obj):
help_string = f"{attr_string}{' ' * (n_spaces - len(attr_string))}{comment}"
help_strings.append(help_string)

return '\n'.join(help_strings)
# Add header info
cli_help_header = []
config_classes = list(figutils.get_config_classes())
if len(config_classes) > 1:
header = (
f"Current config is '{type(config_obj).__name__}'. Available config classes {config_classes}. "
"Set config with --config=OtherConfigClass")
cli_help_header.append(header)

if help_strings:
cli_help_header.append("{}The available input arguments are".format(
'\n' if cli_help_header else ''))

return '\n'.join(cli_help_header + help_strings)


def extract_config_obj_comments(config_obj):
Expand All @@ -56,7 +69,7 @@ def extract_config_obj_comments(config_obj):
comments = _extract_comments(type(config_obj))

# Remove the keys that aren't allowed from command line input
allowed_cli_args = figutils.check_allowed_cli_args(config_obj)
allowed_cli_args = figutils.get_allowed_cli_args(config_obj)
comments = {k: v for k, v in comments.items() if k in allowed_cli_args}

flat_comments = {}
Expand Down
33 changes: 18 additions & 15 deletions hacking/required_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from pathlib import Path
import time
import typing
from anyfig import print_utils


@anyfig.config_class # Registers the class with anyfig
Expand All @@ -16,8 +17,20 @@ def __init__(self):
# The inner config obj
self.innerfig = InnerConfig()

def post_init(self):
print(type(self).__name__)
# self.help = 'heeelp'

# def allowed_cli_args(self):
# pass

# def cli_help(self):
# hej = "YOOOLLOOF"
# cmt = print_utils.cli_help(self)
# return hej + cmt
# return "YOOOLLOOF"

# return ['start_time1']
# return 'start_time', 'innerfig'
# return 'start_time'


@anyfig.config_class
Expand All @@ -26,9 +39,10 @@ def __init__(self):

# An integer between the values of 1 and 10 because the world has never seen such apples
self.inner = 'innner'
self.inner2 = 'innner2'

def post_init(self):
print(type(self).__name__)
def allowed_cli_args(self):
return 11


class InnerConfig2:
Expand All @@ -37,16 +51,5 @@ def __init__(self):
self.inner = 'innner2'


# tt = typing.Union[Path, str]
# tt = str
# print(tt)
# print(type(tt))
config = anyfig.init_config(default_config=MyConfig)
print(config)

# config.frozen(False)
# config.start_time = 123
# print(config)

# config.innerfig.inner = 'HEEJ'
# print(config)
10 changes: 6 additions & 4 deletions notes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,23 @@ Versioning support - I'd like to create a way to keep track of / load old config


Can I use the "with" statement to maybe say with Anyfig.OnlyOverwrite(self) or something to make sure that people don't add new attributes in configs instead of overwritting existing attributes?
"with" statement to set config attributes without having to set frozen(False) then back to frozen(True)

Test frozen for nested obejcts

Move _frozen and other default attributes to a function so it's defined at one place

license as a button in github

when printing available classes in setup, only print the class, not the name.

Make target classes have a special attribute that holds the dict arguments? Good is that you can put other stiff in there, but bad is that it becomes another thing you need to remember about anyfig


type for target class for isinstance check

Assume unchanged instead of that ignore thing in git for user configs? It had some problems when changing branches as git couldn't handle.

--help doesn't work with type hints
Don't allow --help (or -h in config)


~~~~~~ WEBSITE ~~~~~~
Style external links
Expand All @@ -32,4 +33,5 @@ Some sort of info on the main page.
dict cli-arguments readme
cli_input readme
readme save/load. Also write why its difficult
post_init readme. Is this feature done?
post_init readme. Is this feature done? post init can be done to validate config or somethink
allowed_cli_args readme

0 comments on commit 23a0d40

Please sign in to comment.