Skip to content

Commit e04d0a4

Browse files
committed
fixes #107
1 parent e5f2df7 commit e04d0a4

File tree

3 files changed

+86
-36
lines changed

3 files changed

+86
-36
lines changed

fastcore/_nbdev.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@
5252
"mk_class": "02_utils.ipynb",
5353
"wrap_class": "02_utils.ipynb",
5454
"ignore_exceptions": "02_utils.ipynb",
55+
"stop": "02_utils.ipynb",
56+
"AttrDict": "02_utils.ipynb",
5557
"dict2obj": "02_utils.ipynb",
5658
"store_attr": "02_utils.ipynb",
5759
"attrdict": "02_utils.ipynb",
@@ -86,7 +88,6 @@
8688
"in_": "02_utils.ipynb",
8789
"operator.in_": "02_utils.ipynb",
8890
"true": "02_utils.ipynb",
89-
"stop": "02_utils.ipynb",
9091
"gen": "02_utils.ipynb",
9192
"chunked": "02_utils.ipynb",
9293
"trace": "02_utils.ipynb",

fastcore/utils.py

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
# AUTOGENERATED! DO NOT EDIT! File to edit: nbs/02_utils.ipynb (unless otherwise specified).
22

3-
__all__ = ['ifnone', 'maybe_attr', 'basic_repr', 'get_class', 'mk_class', 'wrap_class', 'ignore_exceptions', 'dict2obj',
4-
'store_attr', 'attrdict', 'properties', 'camel2snake', 'snake2camel', 'class2attr', 'hasattrs', 'setattrs',
5-
'ShowPrint', 'Int', 'Str', 'Float', 'tuplify', 'detuplify', 'replicate', 'uniqueify', 'setify', 'merge',
6-
'is_listy', 'range_of', 'groupby', 'last_index', 'shufflish', 'IterLen', 'ReindexCollection', 'num_methods',
7-
'rnum_methods', 'inum_methods', 'fastuple', 'Inf', 'in_', 'lt', 'gt', 'le', 'ge', 'eq', 'ne', 'add', 'sub',
8-
'mul', 'truediv', 'is_', 'is_not', 'in_', 'true', 'stop', 'gen', 'chunked', 'trace', 'compose', 'maps',
9-
'partialler', 'mapped', 'instantiate', 'using_attr', 'Self', 'Self', 'remove_patches_path', 'bunzip',
10-
'join_path_file', 'urlread', 'urljson', 'run', 'do_request', 'sort_by_run', 'PrettyString', 'round_multiple',
11-
'even_mults', 'num_cpus', 'add_props', 'ContextManagers', 'set_num_threads', 'ProcessPoolExecutor',
12-
'ThreadPoolExecutor', 'parallel', 'run_procs', 'parallel_gen']
3+
__all__ = ['ifnone', 'maybe_attr', 'basic_repr', 'get_class', 'mk_class', 'wrap_class', 'ignore_exceptions', 'stop',
4+
'AttrDict', 'dict2obj', 'store_attr', 'attrdict', 'properties', 'camel2snake', 'snake2camel', 'class2attr',
5+
'hasattrs', 'setattrs', 'ShowPrint', 'Int', 'Str', 'Float', 'tuplify', 'detuplify', 'replicate', 'uniqueify',
6+
'setify', 'merge', 'is_listy', 'range_of', 'groupby', 'last_index', 'shufflish', 'IterLen',
7+
'ReindexCollection', 'num_methods', 'rnum_methods', 'inum_methods', 'fastuple', 'Inf', 'in_', 'lt', 'gt',
8+
'le', 'ge', 'eq', 'ne', 'add', 'sub', 'mul', 'truediv', 'is_', 'is_not', 'in_', 'true', 'gen', 'chunked',
9+
'trace', 'compose', 'maps', 'partialler', 'mapped', 'instantiate', 'using_attr', 'Self', 'Self',
10+
'remove_patches_path', 'bunzip', 'join_path_file', 'urlread', 'urljson', 'run', 'do_request', 'sort_by_run',
11+
'PrettyString', 'round_multiple', 'even_mults', 'num_cpus', 'add_props', 'ContextManagers',
12+
'set_num_threads', 'ProcessPoolExecutor', 'ThreadPoolExecutor', 'parallel', 'run_procs', 'parallel_gen']
1313

1414
# Cell
1515
from .imports import *
@@ -87,12 +87,27 @@ class ignore_exceptions:
8787
def __enter__(self): pass
8888
def __exit__(self, *args): return True
8989

90+
# Cell
91+
def stop(e=StopIteration):
92+
"Raises exception `e` (by default `StopException`)"
93+
raise e
94+
95+
# Cell
96+
class AttrDict(GetAttr, dict):
97+
"`dict` subclass that also provides access to keys as attrs"
98+
def _dir(self): return list(self.keys())
99+
def __getattr__(self,k): return self[k] if k in self else stop(AttributeError(k))
100+
def __setattr__(self, k, v):
101+
if k.startswith('_'): super().__setattr__(k,v)
102+
self[k] = v
103+
def __dir__(self): return custom_dir(self,self._dir())
104+
90105
# Cell
91106
def dict2obj(d):
92-
"Convert (possibly nested) dicts (or lists of dicts) to `SimpleNamespace`"
107+
"Convert (possibly nested) dicts (or lists of dicts) to `AttrDict`"
93108
if isinstance(d, (L,list)): return L(d).map(dict2obj)
94109
if not isinstance(d, dict): return d
95-
return SimpleNamespace(**{k:dict2obj(v) for k,v in d.items()})
110+
return AttrDict(**{k:dict2obj(v) for k,v in d.items()})
96111

97112
# Cell
98113
def _store_attr(self, **attrs):
@@ -361,11 +376,6 @@ def true(*args, **kwargs):
361376
"Predicate: always `True`"
362377
return True
363378

364-
# Cell
365-
def stop(e=StopIteration):
366-
"Raises exception `e` (by default `StopException`) even if in an expression"
367-
raise e
368-
369379
# Cell
370380
def gen(func, seq, cond=true):
371381
"Like `(func(o) for o in seq if cond(func(o)))` but handles `StopIteration`"
@@ -569,13 +579,16 @@ def urljson(url):
569579
return json.loads(urlread(url))
570580

571581
# Cell
572-
def run(cmd, *rest):
582+
def run(cmd, *rest, ignore_ex=False, as_bytes=False):
573583
"Pass `cmd` (splitting with `shlex` if string) to `subprocess.run`, returning `stdout`, or raise `IOError` on failure"
574584
if rest: cmd = (cmd,)+rest
575585
elif isinstance(cmd,str): cmd = shlex.split(cmd)
576586
res = subprocess.run(cmd, capture_output=True)
587+
stdout = res.stdout
588+
if not as_bytes: stdout = stdout.decode()
589+
if ignore_ex: return (res.returncode, stdout)
577590
if res.returncode: raise IOError("{} ;; {}".format(res.stdout, res.stderr))
578-
return res.stdout
591+
return stdout
579592

580593
# Cell
581594
def do_request(url, post=False, headers=None, **data):

nbs/02_utils.ipynb

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@
294294
{
295295
"data": {
296296
"text/plain": [
297-
"<__main__._t at 0x7efc6c1ec150>"
297+
"<__main__._t at 0x7f2e862db250>"
298298
]
299299
},
300300
"execution_count": null,
@@ -488,6 +488,53 @@
488488
"These functions reduce boilerplate when setting or manipulating attributes or properties of objects."
489489
]
490490
},
491+
{
492+
"cell_type": "code",
493+
"execution_count": null,
494+
"metadata": {},
495+
"outputs": [],
496+
"source": [
497+
"#export\n",
498+
"def stop(e=StopIteration):\n",
499+
" \"Raises exception `e` (by default `StopException`)\"\n",
500+
" raise e"
501+
]
502+
},
503+
{
504+
"cell_type": "code",
505+
"execution_count": null,
506+
"metadata": {},
507+
"outputs": [],
508+
"source": [
509+
"#export\n",
510+
"class AttrDict(GetAttr, dict):\n",
511+
" \"`dict` subclass that also provides access to keys as attrs\"\n",
512+
" def _dir(self): return list(self.keys())\n",
513+
" def __getattr__(self,k): return self[k] if k in self else stop(AttributeError(k))\n",
514+
" def __setattr__(self, k, v):\n",
515+
" if k.startswith('_'): super().__setattr__(k,v)\n",
516+
" self[k] = v\n",
517+
" def __dir__(self): return custom_dir(self,self._dir())"
518+
]
519+
},
520+
{
521+
"cell_type": "code",
522+
"execution_count": null,
523+
"metadata": {},
524+
"outputs": [],
525+
"source": [
526+
"d = AttrDict(a=1,b=\"two\")\n",
527+
"test_eq(d.a, 1)\n",
528+
"test_eq(d['b'], 'two')\n",
529+
"test_eq(d.get('c','nope'), 'nope')\n",
530+
"d.b = 2\n",
531+
"test_eq(d.b, 2)\n",
532+
"test_eq(d['b'], 2)\n",
533+
"d['b'] = 3\n",
534+
"test_eq(d['b'], 3)\n",
535+
"test_eq(d.b, 3)"
536+
]
537+
},
491538
{
492539
"cell_type": "code",
493540
"execution_count": null,
@@ -496,10 +543,10 @@
496543
"source": [
497544
"#export\n",
498545
"def dict2obj(d):\n",
499-
" \"Convert (possibly nested) dicts (or lists of dicts) to `SimpleNamespace`\"\n",
546+
" \"Convert (possibly nested) dicts (or lists of dicts) to `AttrDict`\"\n",
500547
" if isinstance(d, (L,list)): return L(d).map(dict2obj)\n",
501548
" if not isinstance(d, dict): return d\n",
502-
" return SimpleNamespace(**{k:dict2obj(v) for k,v in d.items()})"
549+
" return AttrDict(**{k:dict2obj(v) for k,v in d.items()})"
503550
]
504551
},
505552
{
@@ -517,7 +564,7 @@
517564
{
518565
"data": {
519566
"text/plain": [
520-
"namespace(a=1, b=namespace(c=2, d=3))"
567+
"{'a': 1, 'b': {'c': 2, 'd': 3}}"
521568
]
522569
},
523570
"execution_count": null,
@@ -529,6 +576,7 @@
529576
"d1 = dict(a=1, b=dict(c=2,d=3))\n",
530577
"d2 = dict2obj(d1)\n",
531578
"test_eq(d2.b.c, 2)\n",
579+
"test_eq(d2.b['c'], 2)\n",
532580
"d2"
533581
]
534582
},
@@ -2293,18 +2341,6 @@
22932341
"assert true([])"
22942342
]
22952343
},
2296-
{
2297-
"cell_type": "code",
2298-
"execution_count": null,
2299-
"metadata": {},
2300-
"outputs": [],
2301-
"source": [
2302-
"#export\n",
2303-
"def stop(e=StopIteration):\n",
2304-
" \"Raises exception `e` (by default `StopException`) even if in an expression\"\n",
2305-
" raise e"
2306-
]
2307-
},
23082344
{
23092345
"cell_type": "code",
23102346
"execution_count": null,

0 commit comments

Comments
 (0)