From 858c408997ce8db09ff24536956b5189f39318ca Mon Sep 17 00:00:00 2001 From: vict0rsch Date: Thu, 4 Nov 2021 18:38:48 -0400 Subject: [PATCH 01/12] missing EOF new line --- requirements-test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-test.txt b/requirements-test.txt index 4eb528b..89f8c7f 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -4,4 +4,4 @@ isort pre-commit pytest pytest-cov -tox \ No newline at end of file +tox From 78dffbc588bd35146ae26b1a6204fb75299264e7 Mon Sep 17 00:00:00 2001 From: vict0rsch Date: Thu, 4 Nov 2021 18:39:45 -0400 Subject: [PATCH 02/12] missing EOF new line --- assets/carbon-config.json | 2 +- examples/demo.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/carbon-config.json b/assets/carbon-config.json index 1aa56be..ebd1bae 100644 --- a/assets/carbon-config.json +++ b/assets/carbon-config.json @@ -1 +1 @@ -{"paddingVertical":"57px","paddingHorizontal":"55px","backgroundImage":null,"backgroundImageSelection":null,"backgroundMode":"color","backgroundColor":"rgba(255,255,255,1)","dropShadow":true,"dropShadowOffsetY":"21px","dropShadowBlurRadius":"45px","theme":"material","windowTheme":"none","language":"text","fontFamily":"MonoLisa","fontSize":"13.5px","lineHeight":"150%","windowControls":true,"widthAdjustment":false,"lineNumbers":false,"firstLineNumber":1,"exportSize":"4x","watermark":false,"squaredImage":false,"hiddenCharacters":false,"name":"","width":912} \ No newline at end of file +{"paddingVertical":"57px","paddingHorizontal":"55px","backgroundImage":null,"backgroundImageSelection":null,"backgroundMode":"color","backgroundColor":"rgba(255,255,255,1)","dropShadow":true,"dropShadowOffsetY":"21px","dropShadowBlurRadius":"45px","theme":"material","windowTheme":"none","language":"text","fontFamily":"MonoLisa","fontSize":"13.5px","lineHeight":"150%","windowControls":true,"widthAdjustment":false,"lineNumbers":false,"firstLineNumber":1,"exportSize":"4x","watermark":false,"squaredImage":false,"hiddenCharacters":false,"name":"","width":912} diff --git a/examples/demo.json b/examples/demo.json index 1408972..a397eed 100644 --- a/examples/demo.json +++ b/examples/demo.json @@ -8,4 +8,4 @@ } }, "verbose": false -} \ No newline at end of file +} From 8813e86f7fd98cce24258c13768d5db5804f52ca Mon Sep 17 00:00:00 2001 From: vict0rsch Date: Thu, 4 Nov 2021 18:40:21 -0400 Subject: [PATCH 03/12] new overriding config --- examples/demo2.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 examples/demo2.json diff --git a/examples/demo2.json b/examples/demo2.json new file mode 100644 index 0000000..5d128f9 --- /dev/null +++ b/examples/demo2.json @@ -0,0 +1,12 @@ +{ + "log": { + "outdir": "/some/other/path", + "project": "demo", + "logger": { + "log_level": "INFO", + "logger_name": "minydra" + } + }, + "verbose": false, + "new_key": 3 +} From f998a5d37010b7ef8b53ab42c664294a53e9a07b Mon Sep 17 00:00:00 2001 From: vict0rsch Date: Thu, 4 Nov 2021 18:40:48 -0400 Subject: [PATCH 04/12] add minydefaults logic --- minydra/__init__.py | 4 ++++ minydra/parser.py | 50 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/minydra/__init__.py b/minydra/__init__.py index 9461ca2..0264776 100644 --- a/minydra/__init__.py +++ b/minydra/__init__.py @@ -10,6 +10,7 @@ def parse_args( warn_overwrites=True, parse_env=True, warn_env=True, + defaults=None, ): def decorator(function): def wrapper(*args, **kwargs): @@ -19,6 +20,7 @@ def wrapper(*args, **kwargs): warn_overwrites=warn_overwrites, parse_env=parse_env, warn_env=warn_env, + defaults=defaults, ) result = function(parser.args) return result @@ -34,6 +36,7 @@ def resolved_args( warn_overwrites=True, parse_env=True, warn_env=True, + defaults=None, ): return Parser( verbose=verbose, @@ -41,4 +44,5 @@ def resolved_args( warn_overwrites=warn_overwrites, parse_env=parse_env, warn_env=warn_env, + defaults=defaults, ).args.resolve() diff --git a/minydra/parser.py b/minydra/parser.py index 40689ed..72011cd 100644 --- a/minydra/parser.py +++ b/minydra/parser.py @@ -2,10 +2,11 @@ import os import re import sys -from typing import Any, List, Optional +from typing import Any, List, Optional, Union from minydra.dict import MinyDict from minydra.exceptions import MinydraWrongArgumentException +from minydra.utils import resolve_path class Parser: @@ -32,6 +33,7 @@ def __init__( warn_overwrites=True, parse_env=True, warn_env=True, + defaults=None, ) -> None: """ Create a Minydra Parser to parse arbitrary commandline argument as: @@ -51,6 +53,9 @@ def __init__( as key or value in the command line. Defaults to True. warn_env (bool, optional): Wether to print a warning in case an environment variable is parsed but no value is found. Defaults to True. + defaults (Union[str, dict, MinyDict], optional): The set of allowed keys as + a (Miny)dict or a path to a file that `minydra.MinyDict` will be able to + load (as `json`, `pickle` or `yaml`) """ super().__init__() @@ -64,6 +69,48 @@ def __init__( self._print("sys.argv:", self._argv) self._parse_args() + if defaults is not None or self.args.minydefaults: + default = self.load_defaults(self.args.minydefaults or defaults) + args = self.args.deepcopy().resolve() + minydefaults = args.minydefaults + if args.minydefaults: + del args.minydefaults + self.args = default.update(args, strict=True) + if minydefaults: + self.args.minydefaults = minydefaults + + @staticmethod + def load_defaults(default: Union[str, dict, MinyDict]): + """ + Set the default keys. + + Args: + allow (Union[str, dict, MinyDict]): The set of allowed keys as a + (Miny)dict or a path to a file that `minydra.MinyDict` will be able to + load (as `json`, `pickle` or `yaml`) + """ + if isinstance(default, str): + default = resolve_path(default) + assert default.exists() + assert default.is_file() + if default.suffix not in {".json", ".yaml", ".yml", ".pickle", ".pkl"}: + raise ValueError(f"{str(default)} is not a valid file extension.") + if default.suffix in {".yaml", ".yml"}: + default = MinyDict.from_yaml(default) + elif default.suffix in {".pickle", ".pkl"}: + default = MinyDict.from_pickle(default) + else: + default = MinyDict.from_json(default) + elif isinstance(default, dict): + default = MinyDict(default).resolve() + elif isinstance(default, list): + defaults = [Parser.load_defaults(d) for d in default] + default = MinyDict() + for d in defaults: + default.update(d, strict=False) + + assert isinstance(default, MinyDict) + return default def _print(self, *args, **kwargs): if self.verbose > 0: @@ -177,7 +224,6 @@ def _force_type(value: str, type_str: str) -> Any: return float(value) if type_str == "str": return str(value) - return value @staticmethod def _infer_arg_type(arg: Any, type_str: Optional[str] = None) -> Any: From b11b6894f77366e184a7525504aa09b051e0f4c4 Mon Sep 17 00:00:00 2001 From: vict0rsch Date: Thu, 4 Nov 2021 18:41:04 -0400 Subject: [PATCH 05/12] fix test typos --- tests/test_parser_static.py | 52 ++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/tests/test_parser_static.py b/tests/test_parser_static.py index 8a1c6d2..0564a14 100644 --- a/tests/test_parser_static.py +++ b/tests/test_parser_static.py @@ -91,42 +91,42 @@ def test_set_env(monkeypatch, capfd): assert "Detected variable $MINY_VAR_DOES_NOT_EXIST" in out -def test_sanitize_args_int(): - assert Parser.sanitize_args({"a": "3"}) == {"a": 3} +def test_parse_arg_types_int(): + assert Parser.parse_arg_types({"a": "3"}) == {"a": 3} -def test_sanitize_args_float(): - assert Parser.sanitize_args({"a": "3.1"}) == {"a": 3.1} - assert Parser.sanitize_args({"a": "1e-4"}) == {"a": 0.0001} +def test_parse_arg_types_float(): + assert Parser.parse_arg_types({"a": "3.1"}) == {"a": 3.1} + assert Parser.parse_arg_types({"a": "1e-4"}) == {"a": 0.0001} -def test_sanitize_args_bool(): - assert Parser.sanitize_args({"a": "true"}) == {"a": True} - assert Parser.sanitize_args({"a": "True"}) == {"a": True} - assert Parser.sanitize_args({"a": "false"}) == {"a": False} - assert Parser.sanitize_args({"a": "False"}) == {"a": False} +def test_parse_arg_types_bool(): + assert Parser.parse_arg_types({"a": "true"}) == {"a": True} + assert Parser.parse_arg_types({"a": "True"}) == {"a": True} + assert Parser.parse_arg_types({"a": "false"}) == {"a": False} + assert Parser.parse_arg_types({"a": "False"}) == {"a": False} -def test_sanitize_args_list(): - assert Parser.sanitize_args({"a": "[]"}) == {"a": []} - assert Parser.sanitize_args({"a": "[1, 2]"}) == {"a": [1, 2]} - assert Parser.sanitize_args({"a": "[1, 2, 'b']"}) == {"a": [1, 2, "b"]} - assert Parser.sanitize_args({"a": "[1, 2, 'b']", "c": 4}) == { +def test_parse_arg_types_list(): + assert Parser.parse_arg_types({"a": "[]"}) == {"a": []} + assert Parser.parse_arg_types({"a": "[1, 2]"}) == {"a": [1, 2]} + assert Parser.parse_arg_types({"a": "[1, 2, 'b']"}) == {"a": [1, 2, "b"]} + assert Parser.parse_arg_types({"a": "[1, 2, 'b']", "c": 4}) == { "a": [1, 2, "b"], "c": 4, } - assert Parser.sanitize_args({"a": "[1, [2, 3]]"}) == {"a": [1, [2, 3]]} - assert Parser.sanitize_args({"a": "[1, [2, 1e-3]]"}) == {"a": [1, [2, 0.001]]} - assert Parser.sanitize_args({"a": "['false']"}) == {"a": [False]} - assert Parser.sanitize_args({"a": "[False]"}) == {"a": [False]} + assert Parser.parse_arg_types({"a": "[1, [2, 3]]"}) == {"a": [1, [2, 3]]} + assert Parser.parse_arg_types({"a": "[1, [2, 1e-3]]"}) == {"a": [1, [2, 0.001]]} + assert Parser.parse_arg_types({"a": "['false']"}) == {"a": [False]} + assert Parser.parse_arg_types({"a": "[False]"}) == {"a": [False]} -def test_sanitize_args_dict(monkeypatch): - assert Parser.sanitize_args({"a": "{}"}) == {"a": {}} - assert Parser.sanitize_args({"a": "{1: 2}"}) == {"a": {1: 2}} - assert Parser.sanitize_args({"a": "{1: 2e-3}"}) == {"a": {1: 0.002}} - assert Parser.sanitize_args({"a": "{1: False}"}) == {"a": {1: False}} - assert Parser.sanitize_args({"a": "{1: [1, 3]}"}) == {"a": {1: [1, 3]}} +def test_parse_arg_types_dict(monkeypatch): + assert Parser.parse_arg_types({"a": "{}"}) == {"a": {}} + assert Parser.parse_arg_types({"a": "{1: 2}"}) == {"a": {1: 2}} + assert Parser.parse_arg_types({"a": "{1: 2e-3}"}) == {"a": {1: 0.002}} + assert Parser.parse_arg_types({"a": "{1: False}"}) == {"a": {1: False}} + assert Parser.parse_arg_types({"a": "{1: [1, 3]}"}) == {"a": {1: [1, 3]}} monkeypatch.setenv("USER", "TestingUser") - assert Parser.sanitize_args({"a": "{1: '$USER'}"}) == {"a": {1: "TestingUser"}} + assert Parser.parse_arg_types({"a": "{1: '$USER'}"}) == {"a": {1: "TestingUser"}} From d38f7249ac52d8860cb99459b320762d94826aad Mon Sep 17 00:00:00 2001 From: vict0rsch Date: Thu, 4 Nov 2021 18:41:33 -0400 Subject: [PATCH 06/12] add defaults tests --- tests/test_minydra.py | 63 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/tests/test_minydra.py b/tests/test_minydra.py index 4142b5e..b94174b 100644 --- a/tests/test_minydra.py +++ b/tests/test_minydra.py @@ -1,7 +1,12 @@ +import json import sys +from pathlib import Path from unittest.mock import patch +import pytest + import minydra +from minydra.dict import MinyDict def test_resolved_args(): @@ -21,3 +26,61 @@ def main(args): assert args.foo == "bar" main() + + +def test_defaults(): + + examples = Path(__file__).resolve().parent.parent / "examples" + d1 = examples / "demo.json" + d2 = examples / "demo2.json" + y1 = examples / "demo.yaml" + + p = MinyDict({"a": "2", "c": 3, "d": {"e": {"f": 4, "g": 5}}}) + pkl = p.to_pickle(Path(__file__).resolve().parent / "test.pkl") + + with patch.object(sys, "argv", [""]): + args = minydra.resolved_args(defaults=p) + assert args == p + + with patch.object(sys, "argv", ["", "d.e.f=2"]): + args = minydra.resolved_args(defaults=p) + assert args.d.e.f == 2 + + with patch.object(sys, "argv", ["", f"minydefaults={str(d1)}"]): + args = minydra.resolved_args() + del args.minydefaults + assert args.to_dict() == json.loads(d1.read_text()) + + with patch.object(sys, "argv", ["", f"minydefaults={str(y1)}"]): + args = minydra.resolved_args() + del args.minydefaults + assert args.to_dict() == MinyDict.from_yaml(y1) + + with patch.object(sys, "argv", ["", f"minydefaults={str(pkl)}"]): + args = minydra.resolved_args() + del args.minydefaults + assert args.to_dict() == MinyDict.from_pickle(pkl) + Path(pkl).unlink() + + with pytest.raises(ValueError): + with patch.object( + sys, "argv", ["", f"minydefaults={str(d1).replace('.json', '.py')}"] + ): + args = minydra.resolved_args() + + with pytest.raises(KeyError): + with patch.object(sys, "argv", ["", f"minydefaults={str(d1)}", "new_key=3"]): + args = minydra.resolved_args() + del args.minydefaults + assert args.to_dict() == json.loads(d1.read_text()) + + double_defaults = f"['{str(d1)}', '{str(d2)}']" + with patch.object( + sys, "argv", ["", f"minydefaults={double_defaults}", "new_key=3"] + ): + args = minydra.resolved_args() + d1d = MinyDict.from_json(d1) + d2d = MinyDict.from_json(d2) + d1d = d1d.update(d2d) + del args.minydefaults + assert args == d1d From 6c6ba5981de038d62a8e61353ee7f3a240422238 Mon Sep 17 00:00:00 2001 From: vict0rsch Date: Thu, 4 Nov 2021 19:06:44 -0400 Subject: [PATCH 07/12] use @defaults for the keword --- minydra/parser.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/minydra/parser.py b/minydra/parser.py index 72011cd..2b6166a 100644 --- a/minydra/parser.py +++ b/minydra/parser.py @@ -1,5 +1,6 @@ import ast import os +import pathlib import re import sys from typing import Any, List, Optional, Union @@ -69,15 +70,15 @@ def __init__( self._print("sys.argv:", self._argv) self._parse_args() - if defaults is not None or self.args.minydefaults: - default = self.load_defaults(self.args.minydefaults or defaults) + if defaults is not None or self.args["@defaults"]: + default = self.load_defaults(self.args["@defaults"] or defaults) args = self.args.deepcopy().resolve() - minydefaults = args.minydefaults - if args.minydefaults: - del args.minydefaults + args_defaults = args["@defaults"] + if args["@defaults"]: + del args["@defaults"] self.args = default.update(args, strict=True) - if minydefaults: - self.args.minydefaults = minydefaults + if args_defaults: + self.args["@defaults"] = args_defaults @staticmethod def load_defaults(default: Union[str, dict, MinyDict]): @@ -89,7 +90,7 @@ def load_defaults(default: Union[str, dict, MinyDict]): (Miny)dict or a path to a file that `minydra.MinyDict` will be able to load (as `json`, `pickle` or `yaml`) """ - if isinstance(default, str): + if isinstance(default, (str, pathlib.Path)): default = resolve_path(default) assert default.exists() assert default.is_file() From 087deff25a023bcb78ac1d6f35e63a7c80012ee7 Mon Sep 17 00:00:00 2001 From: vict0rsch Date: Thu, 4 Nov 2021 19:12:13 -0400 Subject: [PATCH 08/12] remove 1 key to show difference --- examples/demo2.json | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/demo2.json b/examples/demo2.json index 5d128f9..aba4456 100644 --- a/examples/demo2.json +++ b/examples/demo2.json @@ -1,7 +1,6 @@ { "log": { "outdir": "/some/other/path", - "project": "demo", "logger": { "log_level": "INFO", "logger_name": "minydra" From 55480cbdeee5586a56f43470567dcf1f423f52d6 Mon Sep 17 00:00:00 2001 From: vict0rsch Date: Thu, 4 Nov 2021 19:12:24 -0400 Subject: [PATCH 09/12] rename to @defaults --- tests/test_minydra.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/tests/test_minydra.py b/tests/test_minydra.py index b94174b..c637d15 100644 --- a/tests/test_minydra.py +++ b/tests/test_minydra.py @@ -46,41 +46,39 @@ def test_defaults(): args = minydra.resolved_args(defaults=p) assert args.d.e.f == 2 - with patch.object(sys, "argv", ["", f"minydefaults={str(d1)}"]): + with patch.object(sys, "argv", ["", f"@defaults={str(d1)}"]): args = minydra.resolved_args() - del args.minydefaults + del args["@defaults"] assert args.to_dict() == json.loads(d1.read_text()) - with patch.object(sys, "argv", ["", f"minydefaults={str(y1)}"]): + with patch.object(sys, "argv", ["", f"@defaults={str(y1)}"]): args = minydra.resolved_args() - del args.minydefaults + del args["@defaults"] assert args.to_dict() == MinyDict.from_yaml(y1) - with patch.object(sys, "argv", ["", f"minydefaults={str(pkl)}"]): + with patch.object(sys, "argv", ["", f"@defaults={str(pkl)}"]): args = minydra.resolved_args() - del args.minydefaults + del args["@defaults"] assert args.to_dict() == MinyDict.from_pickle(pkl) Path(pkl).unlink() with pytest.raises(ValueError): with patch.object( - sys, "argv", ["", f"minydefaults={str(d1).replace('.json', '.py')}"] + sys, "argv", ["", f"@defaults={str(d1).replace('.json', '.py')}"] ): args = minydra.resolved_args() with pytest.raises(KeyError): - with patch.object(sys, "argv", ["", f"minydefaults={str(d1)}", "new_key=3"]): + with patch.object(sys, "argv", ["", f"@defaults={str(d1)}", "new_key=3"]): args = minydra.resolved_args() - del args.minydefaults + del args["@defaults"] assert args.to_dict() == json.loads(d1.read_text()) double_defaults = f"['{str(d1)}', '{str(d2)}']" - with patch.object( - sys, "argv", ["", f"minydefaults={double_defaults}", "new_key=3"] - ): + with patch.object(sys, "argv", ["", f"@defaults={double_defaults}", "new_key=3"]): args = minydra.resolved_args() d1d = MinyDict.from_json(d1) d2d = MinyDict.from_json(d2) d1d = d1d.update(d2d) - del args.minydefaults + del args["@defaults"] assert args == d1d From 9d4d377af548b5d464992d2858ef28e8adee4fbe Mon Sep 17 00:00:00 2001 From: vict0rsch Date: Thu, 4 Nov 2021 19:12:39 -0400 Subject: [PATCH 10/12] add docs and examples --- README.md | 62 +++++++++++++++++++++++++++++++++++++++++ examples/Readme.md | 66 ++++++++++++++++++++++++++++++++++++++++++++ examples/defaults.py | 8 ++++++ 3 files changed, 136 insertions(+) create mode 100644 examples/defaults.py diff --git a/README.md b/README.md index 583d37a..1b072f1 100644 --- a/README.md +++ b/README.md @@ -336,6 +336,68 @@ KeyError: 'Cannot create a non-existing key in strict mode ({"log_leveel":INFO})
+### Using default configurations + +The `minydra.Parser` class takes a `defaults=` keyword argument. This can be: + +* a `str` or a `pathlib.Path` to a `json` `yaml` or `pickle` file that `minydra.MinyDict` can load (`from_X`) +* a `dict` or a `minydra.MinyDict` + +When `defaults` is provided, the resulting `minydra.MinyDict` serves as a reference for the arguments parsed from the command-line: + +* arguments from the command-line have a higher priority but **must** be present in the `defaults` (`defaults.update(args, strict=True)` is used, see [strict mode](#strict-mode)) +* arguments not present in the command-line with fallback to values in `defaults` + +`defaults` can actually be a `list` and the update order is the same as the list's. For instance: + +```python +In [1]: from minydra import Parser + +In [2]: Parser(defaults=["./examples/demo.json", "./examples/demo2.json"]).args.pretty_print(); +╭─────────────────────────────────╮ +│ log │ +│ │logger │ +│ │ │log_level : INFO │ +│ │ │logger_name : minydra │ +│ │outdir : /some/other/path │ +│ │project : demo │ +│ new_key : 3 │ +│ verbose : False │ +╰─────────────────────────────────╯ +``` + +If you need to set defaults from the command-line, there's a special `@defaults` keyword you can use: + + +```text +$ python examples/decorator.py @defaults=./examples/demo.json +╭──────────────────────────────────────╮ +│ @defaults : ./examples/demo.json │ +│ log │ +│ │logger │ +│ │ │log_level : DEBUG │ +│ │ │logger_name : minydra │ +│ │outdir : /some/path │ +│ │project : demo │ +│ verbose : False │ +╰──────────────────────────────────────╯ + +$ python examples/decorator.py @defaults="['./examples/demo.json', './examples/demo2.json']" +╭───────────────────────────────────────────────────────────────────╮ +│ @defaults : ['./examples/demo.json', './examples/demo2.json'] │ +│ log │ +│ │logger │ +│ │ │log_level : INFO │ +│ │ │logger_name : minydra │ +│ │outdir : /some/other/path │ +│ │project : demo │ +│ new_key : 3 │ +│ verbose : False │ +╰───────────────────────────────────────────────────────────────────╯ +``` + +
+ ### `pretty_print` Prints the `MinyDict` in a box, with dicts properly indented. A few arguments: diff --git a/examples/Readme.md b/examples/Readme.md index 8acddae..457cdec 100644 --- a/examples/Readme.md +++ b/examples/Readme.md @@ -297,6 +297,72 @@ In [6]: d.update({"b": {"e": 2}}).pretty_print() # default is strict=False, allo Out[6]: {'a': 10, 'b': {'c': 0, 'e': 2}} ``` +## Using default configurations + +Code: [**`defaults.py`**](defaults.py) + +```python +from minydra import resolved_args + +if __name__ == "__main__": + + args = resolved_args(defaults="demo.yaml") + args.pretty_print() +``` + +```text +$ python examples/defaults.py +╭──────────────────────────────╮ +│ log │ +│ │logger │ +│ │ │log_level : DEBUG │ +│ │ │logger_name : minydra │ +│ │outdir : /some/path │ +│ │project : demo │ +│ verbose : False │ +╰──────────────────────────────╯ + +$ python examples/defaults.py @defaults=examples/demo2.json +╭─────────────────────────────────────╮ +│ @defaults : examples/demo2.json │ +│ log │ +│ │logger │ +│ │ │log_level : INFO │ +│ │ │logger_name : minydra │ +│ │outdir : /some/other/path │ +│ new_key : 3 │ +│ verbose : False │ +╰─────────────────────────────────────╯ + +$ python examples/defaults.py @defaults="['examples/demo.json', 'examples/demo2.json']" +╭───────────────────────────────────────────────────────────────╮ +│ @defaults : ['examples/demo.json', 'examples/demo2.json'] │ +│ log │ +│ │logger │ +│ │ │log_level : INFO │ +│ │ │logger_name : minydra │ +│ │outdir : /some/other/path │ +│ │project : demo │ +│ new_key : 3 │ +│ verbose : False │ +╰───────────────────────────────────────────────────────────────╯ +``` + +```python +In [1]: from minydra import Parser + +In [2]: Parser(defaults=["./examples/demo.json", "./examples/demo2.json"]).args.pretty_print(); +╭─────────────────────────────────╮ +│ log │ +│ │logger │ +│ │ │log_level : INFO │ +│ │ │logger_name : minydra │ +│ │outdir : /some/other/path │ +│ │project : demo │ +│ new_key : 3 │ +│ verbose : False │ +╰─────────────────────────────────╯ +``` ## Protected attributes `MinyDict`'s methods (including the `dict` class's) are protected, they are read-only and you cannot therefore set _attributes_ with there names, like `args.get = 2`. If you do need to have a `get` argument, you can access it through _items_: `args["get"] = 2`. diff --git a/examples/defaults.py b/examples/defaults.py new file mode 100644 index 0000000..b69466f --- /dev/null +++ b/examples/defaults.py @@ -0,0 +1,8 @@ +from pathlib import Path + +from minydra import resolved_args + +if __name__ == "__main__": + + args = resolved_args(defaults=Path(__file__).parent / "demo.yaml") + args.pretty_print() From ad4c061207bd6b9f800478cb6fd3a21b9ef72452 Mon Sep 17 00:00:00 2001 From: vict0rsch Date: Thu, 4 Nov 2021 19:13:32 -0400 Subject: [PATCH 11/12] bump version --- README.md | 4 ++-- minydra/__init__.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1b072f1..591915d 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,8 @@ Easily parse arbitrary arguments from the command line without dependencies: ![example code](assets/code.png) ![example code](assets/run.png) -![](https://img.shields.io/badge/coverage-97%25-success) -![](https://img.shields.io/badge/version-0.1.4-informational) +![](https://img.shields.io/badge/coverage-99%25-success) +![](https://img.shields.io/badge/version-0.1.5-informational) ![](https://img.shields.io/badge/python-3.7%2B%20-orange) ```bash diff --git a/minydra/__init__.py b/minydra/__init__.py index 0264776..375c53a 100644 --- a/minydra/__init__.py +++ b/minydra/__init__.py @@ -1,7 +1,7 @@ from .dict import MinyDict # noqa: F401 from .parser import Parser -__version__ = "0.1.4" +__version__ = "0.1.5" def parse_args( From 98fac59af5deb66ab4b557cae845314d57bdb5cb Mon Sep 17 00:00:00 2001 From: vict0rsch Date: Thu, 4 Nov 2021 19:15:09 -0400 Subject: [PATCH 12/12] update top links --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 591915d..ebf380b 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ pip install minydra MinyDict  •  Save config  •  Prevent typos  •  + Use default configs  •  Examples