From 1b96df65b79f1d56a37b65cd04ffa10910b37259 Mon Sep 17 00:00:00 2001 From: Jeremy Howard Date: Sun, 11 Oct 2020 22:13:44 -0700 Subject: [PATCH] fixes #125 --- fastcore/__init__.py | 2 +- fastcore/_nbdev.py | 1 + fastcore/foundation.py | 8 +++---- fastcore/utils.py | 21 +++++++++++++++-- nbs/01_foundation.ipynb | 12 +++++----- nbs/02_utils.ipynb | 50 ++++++++++++++++++++++++++++++++++++++--- settings.ini | 2 +- 7 files changed, 79 insertions(+), 17 deletions(-) diff --git a/fastcore/__init__.py b/fastcore/__init__.py index a82b376d..72f26f59 100644 --- a/fastcore/__init__.py +++ b/fastcore/__init__.py @@ -1 +1 @@ -__version__ = "1.1.1" +__version__ = "1.1.2" diff --git a/fastcore/_nbdev.py b/fastcore/_nbdev.py index cca82a19..1a2cda0f 100644 --- a/fastcore/_nbdev.py +++ b/fastcore/_nbdev.py @@ -131,6 +131,7 @@ "defaults.cpus": "02_utils.ipynb", "add_props": "02_utils.ipynb", "ContextManagers": "02_utils.ipynb", + "typed": "02_utils.ipynb", "set_num_threads": "02_utils.ipynb", "ProcessPoolExecutor": "02_utils.ipynb", "ThreadPoolExecutor": "02_utils.ipynb", diff --git a/fastcore/foundation.py b/fastcore/foundation.py index 09cf0897..f05b550d 100644 --- a/fastcore/foundation.py +++ b/fastcore/foundation.py @@ -422,15 +422,15 @@ def setattrs(self, attr, val): [setattr(o,attr,val) for o in self] Sequence.register(L); # Cell -def save_config_file(file, d): +def save_config_file(file, d, **kwargs): "Write settings dict to a new config file, or overwrite the existing one." - config = ConfigParser() + config = ConfigParser(**kwargs) config['DEFAULT'] = d config.write(open(file, 'w')) # Cell -def read_config_file(file): - config = ConfigParser() +def read_config_file(file, **kwargs): + config = ConfigParser(**kwargs) config.read(file) return config diff --git a/fastcore/utils.py b/fastcore/utils.py index ad7f587c..ec2ae8d4 100644 --- a/fastcore/utils.py +++ b/fastcore/utils.py @@ -9,8 +9,8 @@ 'inum_methods', 'fastuple', 'trace', 'compose', 'maps', 'partialler', 'mapped', 'instantiate', 'using_attr', 'Self', 'Self', 'save_pickle', 'load_pickle', 'bunzip', 'join_path_file', 'urlread', 'urljson', 'run', 'do_request', 'sort_by_run', 'PrettyString', 'round_multiple', 'even_mults', 'num_cpus', 'add_props', - 'ContextManagers', 'set_num_threads', 'ProcessPoolExecutor', 'ThreadPoolExecutor', 'parallel', 'run_procs', - 'parallel_gen', 'threaded'] + 'ContextManagers', 'typed', 'set_num_threads', 'ProcessPoolExecutor', 'ThreadPoolExecutor', 'parallel', + 'run_procs', 'parallel_gen', 'threaded'] # Cell from .imports import * @@ -675,6 +675,23 @@ def __init__(self, mgrs): self.default,self.stack = L(mgrs),ExitStack() def __enter__(self): self.default.map(self.stack.enter_context) def __exit__(self, *args, **kwargs): self.stack.__exit__(*args, **kwargs) +# Cell +def typed(f): + "Decorator to check param and return types at runtime" + names = f.__code__.co_varnames + anno = f.__annotations__ + ret = anno.pop('return',None) + def _f(*args,**kwargs): + kw = {**kwargs} + if len(anno) > 0: + for i,arg in enumerate(args): kw[names[i]] = arg + for k,v in kw.items(): + if not isinstance(v,anno[k]): raise TypeError(f"{k}=={v} not {anno[k]}") + res = f(*args,**kwargs) + if ret is not None and not isinstance(res,ret): raise TypeError(f"return=={res} not {ret}") + return res + return functools.update_wrapper(_f, f) + # Cell from multiprocessing import Process, Queue import concurrent.futures diff --git a/nbs/01_foundation.ipynb b/nbs/01_foundation.ipynb index 6e6c4b17..0d8b85e1 100644 --- a/nbs/01_foundation.ipynb +++ b/nbs/01_foundation.ipynb @@ -1964,7 +1964,7 @@ { "data": { "text/plain": [ - "['k', 4, 'j']" + "[0, 9, 1]" ] }, "execution_count": null, @@ -2143,7 +2143,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Class L Methods" + "### `L` Methods" ] }, { @@ -3036,9 +3036,9 @@ "outputs": [], "source": [ "#export\n", - "def save_config_file(file, d):\n", + "def save_config_file(file, d, **kwargs):\n", " \"Write settings dict to a new config file, or overwrite the existing one.\"\n", - " config = ConfigParser()\n", + " config = ConfigParser(**kwargs)\n", " config['DEFAULT'] = d\n", " config.write(open(file, 'w'))" ] @@ -3050,8 +3050,8 @@ "outputs": [], "source": [ "#export\n", - "def read_config_file(file):\n", - " config = ConfigParser()\n", + "def read_config_file(file, **kwargs):\n", + " config = ConfigParser(**kwargs)\n", " config.read(file)\n", " return config" ] diff --git a/nbs/02_utils.ipynb b/nbs/02_utils.ipynb index 6aac071d..4802a326 100644 --- a/nbs/02_utils.ipynb +++ b/nbs/02_utils.ipynb @@ -296,7 +296,7 @@ { "data": { "text/plain": [ - "<__main__._t at 0x7ff9a9c3deb0>" + "<__main__._t at 0x7f945b39e070>" ] }, "execution_count": null, @@ -2171,7 +2171,7 @@ { "data": { "text/plain": [ - "['g', 'd', 'h', 'a', 'f', 'c', 'b', 'e']" + "['h', 'g', 'f', 'b', 'd', 'e', 'a', 'c']" ] }, "execution_count": null, @@ -3513,7 +3513,7 @@ { "data": { "text/plain": [ - "64" + "8" ] }, "execution_count": null, @@ -3621,6 +3621,50 @@ "show_doc(ContextManagers, title_level=4)" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#export\n", + "def typed(f):\n", + " \"Decorator to check param and return types at runtime\"\n", + " names = f.__code__.co_varnames\n", + " anno = f.__annotations__\n", + " ret = anno.pop('return',None)\n", + " def _f(*args,**kwargs):\n", + " kw = {**kwargs}\n", + " if len(anno) > 0:\n", + " for i,arg in enumerate(args): kw[names[i]] = arg\n", + " for k,v in kw.items():\n", + " if not isinstance(v,anno[k]): raise TypeError(f\"{k}=={v} not {anno[k]}\")\n", + " res = f(*args,**kwargs)\n", + " if ret is not None and not isinstance(res,ret): raise TypeError(f\"return=={res} not {ret}\")\n", + " return res\n", + " return functools.update_wrapper(_f, f)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "@typed\n", + "def foo(a:int, b:str='a'): return a\n", + "test_eq(foo(1, '2'), 1)\n", + "test_fail(partial(foo, 1, 2))\n", + "\n", + "@typed\n", + "def foo()->str: return 1\n", + "test_fail(partial(foo))\n", + "\n", + "@typed\n", + "def foo()->str: return '1'\n", + "assert foo()" + ] + }, { "cell_type": "markdown", "metadata": {}, diff --git a/settings.ini b/settings.ini index 790b00f0..dddd2249 100644 --- a/settings.ini +++ b/settings.ini @@ -7,7 +7,7 @@ author = Jeremy Howard and Sylvain Gugger author_email = infos@fast.ai copyright = fast.ai branch = master -version = 1.1.1 +version = 1.1.2 min_python = 3.6 audience = Developers language = English