Skip to content

Commit

Permalink
Supports --help for type hinted configs
Browse files Browse the repository at this point in the history
  • Loading branch information
OlofHarrysson committed Sep 13, 2020
1 parent 3dd575a commit 8bcc8d6
Show file tree
Hide file tree
Showing 8 changed files with 45 additions and 53 deletions.
5 changes: 2 additions & 3 deletions anyfig/anyfig_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
7 changes: 7 additions & 0 deletions anyfig/config_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,20 @@ 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)

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):
Expand Down
8 changes: 8 additions & 0 deletions anyfig/figutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
2 changes: 2 additions & 0 deletions anyfig/print_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
54 changes: 11 additions & 43 deletions hacking/required_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
15 changes: 12 additions & 3 deletions notes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions website/docs/fundamentals.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
4 changes: 2 additions & 2 deletions website/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module.exports = {

{
type: 'category',
label: 'Getting Started',
label: 'Get Started',
collapsed: false,
items: ['introduction', 'installation'],
},
Expand All @@ -22,4 +22,4 @@ module.exports = {

],

};
};

0 comments on commit 8bcc8d6

Please sign in to comment.