diff --git a/anyfig/anyfig_setup.py b/anyfig/anyfig_setup.py index 2b3f144..59f80dd 100644 --- a/anyfig/anyfig_setup.py +++ b/anyfig/anyfig_setup.py @@ -48,9 +48,8 @@ def init_config(default_config, cli_args=None): # Overwrite parameters via optional input flags config = overwrite(config, cli_args) - # Perform post init after input flags - if hasattr(config, 'post_init') and inspect.ismethod(config.post_init): - config.post_init() + # Perform deep post init after input flags + figutils.post_init(config) # Unwrap the field values fields.resolve_fields(config) diff --git a/anyfig/config_functions.py b/anyfig/config_functions.py index 4dcdabe..7794c09 100644 --- a/anyfig/config_functions.py +++ b/anyfig/config_functions.py @@ -18,6 +18,10 @@ def allowed_cli_args(self): ''' Returns the attribute names that can be be overwritten from command line input ''' return self.get_parameters() + 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) @@ -25,6 +29,9 @@ def comments_string(self): def frozen(self, freeze=True): ''' Freeze/unfreeze config ''' self._frozen = freeze + for _, val in self.get_parameters(copy=False).items(): + if figutils.is_config_class(val): + val.frozen(freeze) return self def get_parameters(self, copy=True): diff --git a/anyfig/figutils.py b/anyfig/figutils.py index 30684ae..157d75a 100644 --- a/anyfig/figutils.py +++ b/anyfig/figutils.py @@ -139,3 +139,11 @@ def check_allowed_cli_args(config_obj): "input argument") raise AttributeError(err_msg) return allowed_items + + +def post_init(config_obj): + ''' Recursively calls the post_init method on a config and it's attributes ''' + config_obj.post_init() + for _, val in config_obj.get_parameters(copy=False).items(): + if is_config_class(val): + post_init(val) diff --git a/anyfig/print_utils.py b/anyfig/print_utils.py index 0292e6e..74b649c 100644 --- a/anyfig/print_utils.py +++ b/anyfig/print_utils.py @@ -96,6 +96,8 @@ def _extract_comments(class_type): # Extract attribute name attribute_name = code_line.split('=')[0] + if ':' in attribute_name: + attribute_name = attribute_name.split(':')[0] attribute_name = attribute_name.strip().replace('self.', '', 1) # Override parent comment diff --git a/hacking/required_cli.py b/hacking/required_cli.py index fb11536..744eb05 100644 --- a/hacking/required_cli.py +++ b/hacking/required_cli.py @@ -9,62 +9,28 @@ class MyConfig: def __init__(self): # Note help - self.experiment_note = 'Changed stuff' + self.experiment_note: str = 'Changed stuff' # Start help self.start_time = time.time() # The inner config obj - # self.innerfig = InnerConfig() - - # self.save = anyfig.field(int, lambda x: x > 10) - - # TEST1 - # self.save = anyfig.field(typing.Union[Path, str]) - - # self.save = anyfig.constant(12312) - - # self.save = anyfig.field(str) - # self.save = anyfig.field(str) - # self.save = 'bajs' - - # self.save = anyfig.cli_input(str) - # self.save = anyfig.cli_input(int) - # self.save = anyfig.cli_input(list) - # self.save = anyfig.cli_input(dict) - # self.save = anyfig.cli_input(typing.List[int]) - - # self.save = 'hej' - - # self.post_init = 'asdas' - - # def allowed_cli_args(self): - # return ['save', 'asdasd'] - # return ['save', 'innerfig'] + self.innerfig = InnerConfig() def post_init(self): - print("POST INIIIIIT") + print(type(self).__name__) @anyfig.config_class class InnerConfig: def __init__(self): - # ''' Hej - # det går - # braa''' - # self.inner = anyfig.cli_input(str) # An integer between the values of 1 and 10 because the world has never seen such apples self.inner = 'innner' - # HEHE - self.innerasdasdasdasdasd = 'iasdasdasdasdnnner' - - # def allowed_cli_args(self): - # return ['inner'] - # return [] + def post_init(self): + print(type(self).__name__) -@anyfig.config_class class InnerConfig2: def __init__(self): # Note help @@ -78,7 +44,9 @@ def __init__(self): config = anyfig.init_config(default_config=MyConfig) print(config) -# import argparse -# parser = argparse.ArgumentParser() -# parser.add_argument('s', help='hahahah') -# parser.parse_args() +# config.frozen(False) +# config.start_time = 123 +# print(config) + +# config.innerfig.inner = 'HEEJ' +# print(config) diff --git a/notes.txt b/notes.txt index f2984c9..f2735eb 100644 --- a/notes.txt +++ b/notes.txt @@ -5,12 +5,21 @@ 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? +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 -Post init to help constructions objects from input arguments? To put e.g. objects of lists into the config they can't take input arguments. Could also unfreeze the config and have people manually call the function. -Better to decorate a method as anyfig.post_init and have that function called in setup -Can I communicate that post_init and allowed_cli are affected by anyfig? Now they look like normal functions but it's not clear when they are called +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 + + +--help doesn't work with type hints ~~~~~~ WEBSITE ~~~~~~ Style external links diff --git a/website/docs/fundamentals.mdx b/website/docs/fundamentals.mdx index ac856a1..f3dd74f 100644 --- a/website/docs/fundamentals.mdx +++ b/website/docs/fundamentals.mdx @@ -103,8 +103,7 @@ Most people pass the config-object around their code, accessing the config-value Global objects are often considered bad practice because multiple components can change the same global object which complicates understandability and debugging. Anyfig's config-objects are **immutable by default** to mitigate this. ```python title="my_project/another_file.py" -from anyfig import get_config -from anyfig import global_cfg +from anyfig import global_cfg, get_config class SomeClass: def __init__(self): diff --git a/website/sidebars.js b/website/sidebars.js index c2e6b0f..85d1e9c 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -3,7 +3,7 @@ module.exports = { { type: 'category', - label: 'Getting Started', + label: 'Get Started', collapsed: false, items: ['introduction', 'installation'], }, @@ -22,4 +22,4 @@ module.exports = { ], -}; \ No newline at end of file +};