Skip to content

Commit 82e374d

Browse files
committed
fixes #271
1 parent 0e3084e commit 82e374d

File tree

4 files changed

+55
-103
lines changed

4 files changed

+55
-103
lines changed

examples/test_fastcore.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
@call_parse
66
def main(msg:Param("The message", str),
7-
upper:Param("Convert to uppercase?", store_true)):
7+
upper:Param("Convert to uppercase?", store_true)=False):
88
"Print `msg`, optionally converting to uppercase"
99
print(msg.upper() if upper else msg)
1010

fastcore/_nbdev.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@
149149
"bunzip": "03_xtras.ipynb",
150150
"join_path_file": "03_xtras.ipynb",
151151
"loads": "03_xtras.ipynb",
152+
"loads_multi": "03_xtras.ipynb",
152153
"untar_dir": "03_xtras.ipynb",
153154
"repo_details": "03_xtras.ipynb",
154155
"run": "03_xtras.ipynb",
@@ -175,7 +176,6 @@
175176
"modified_env": "03_xtras.ipynb",
176177
"ContextManagers": "03_xtras.ipynb",
177178
"str2bool": "03_xtras.ipynb",
178-
"sort_by_run": "03_xtras.ipynb",
179179
"threaded": "03a_parallel.ipynb",
180180
"startthread": "03a_parallel.ipynb",
181181
"set_num_threads": "03a_parallel.ipynb",

fastcore/xtras.py

Lines changed: 16 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# AUTOGENERATED! DO NOT EDIT! File to edit: nbs/03_xtras.ipynb (unless otherwise specified).
22

33
__all__ = ['dict2obj', 'obj2dict', 'repr_dict', 'is_listy', 'shufflish', 'mapped', 'IterLen', 'ReindexCollection',
4-
'maybe_open', 'image_size', 'bunzip', 'join_path_file', 'loads', 'untar_dir', 'repo_details', 'run',
5-
'open_file', 'save_pickle', 'load_pickle', 'truncstr', 'spark_chars', 'sparkline', 'autostart', 'EventTimer',
6-
'stringfmt_names', 'PartialFormatter', 'partial_format', 'utc2local', 'local2utc', 'trace', 'round_multiple',
7-
'modified_env', 'ContextManagers', 'str2bool', 'sort_by_run']
4+
'maybe_open', 'image_size', 'bunzip', 'join_path_file', 'loads', 'loads_multi', 'untar_dir', 'repo_details',
5+
'run', 'open_file', 'save_pickle', 'load_pickle', 'truncstr', 'spark_chars', 'sparkline', 'autostart',
6+
'EventTimer', 'stringfmt_names', 'PartialFormatter', 'partial_format', 'utc2local', 'local2utc', 'trace',
7+
'round_multiple', 'modified_env', 'ContextManagers', 'str2bool']
88

99
# Cell
1010
from .imports import *
@@ -136,6 +136,17 @@ def loads(s, cls=None, object_hook=None, parse_float=None,
136136
return json.loads(s, cls=cls, object_hook=object_hook, parse_float=parse_float,
137137
parse_int=parse_int, parse_constant=parse_constant, object_pairs_hook=object_pairs_hook, **kw)
138138

139+
# Cell
140+
def loads_multi(s:str):
141+
"Generator of >=0 decoded json dicts, possibly with non-json ignored text at start and end"
142+
_dec = json.JSONDecoder()
143+
while s.find('{')>=0:
144+
s = s[s.find('{'):]
145+
obj,pos = _dec.raw_decode(s)
146+
if not pos: raise ValueError(f'no JSON object found at {pos}')
147+
yield obj
148+
s = s[pos:]
149+
139150
# Cell
140151
def untar_dir(file, dest):
141152
with tempfile.TemporaryDirectory(dir='.') as d:
@@ -357,29 +368,4 @@ def __exit__(self, *args, **kwargs): self.stack.__exit__(*args, **kwargs)
357368
def str2bool(s):
358369
"Case-insensitive convert string `s` too a bool (`y`,`yes`,`t`,`true`,`on`,`1`->`True`)"
359370
if not isinstance(s,str): return bool(s)
360-
return bool(distutils.util.strtobool(s)) if s else False
361-
362-
# Cell
363-
def _is_instance(f, gs):
364-
tst = [g if type(g) in [type, 'function'] else g.__class__ for g in gs]
365-
for g in tst:
366-
if isinstance(f, g) or f==g: return True
367-
return False
368-
369-
def _is_first(f, gs):
370-
for o in L(getattr(f, 'run_after', None)):
371-
if _is_instance(o, gs): return False
372-
for g in gs:
373-
if _is_instance(f, L(getattr(g, 'run_before', None))): return False
374-
return True
375-
376-
def sort_by_run(fs):
377-
end = L(fs).attrgot('toward_end')
378-
inp,res = L(fs)[~end] + L(fs)[end], L()
379-
while len(inp):
380-
for i,o in enumerate(inp):
381-
if _is_first(o, inp):
382-
res.append(inp.pop(i))
383-
break
384-
else: raise Exception("Impossible to sort")
385-
return res
371+
return bool(distutils.util.strtobool(s)) if s else False

nbs/03_xtras.ipynb

Lines changed: 37 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -618,7 +618,7 @@
618618
{
619619
"data": {
620620
"text/plain": [
621-
"['a', 'f', 'b', 'g', 'd', 'e', 'h', 'c']"
621+
"['b', 'a', 'd', 'e', 'f', 'h', 'g', 'c']"
622622
]
623623
},
624624
"execution_count": null,
@@ -963,6 +963,42 @@
963963
" parse_int=parse_int, parse_constant=parse_constant, object_pairs_hook=object_pairs_hook, **kw)"
964964
]
965965
},
966+
{
967+
"cell_type": "code",
968+
"execution_count": null,
969+
"metadata": {},
970+
"outputs": [],
971+
"source": [
972+
"#export\n",
973+
"def loads_multi(s:str):\n",
974+
" \"Generator of >=0 decoded json dicts, possibly with non-json ignored text at start and end\"\n",
975+
" _dec = json.JSONDecoder()\n",
976+
" while s.find('{')>=0:\n",
977+
" s = s[s.find('{'):]\n",
978+
" obj,pos = _dec.raw_decode(s)\n",
979+
" if not pos: raise ValueError(f'no JSON object found at {pos}')\n",
980+
" yield obj\n",
981+
" s = s[pos:]"
982+
]
983+
},
984+
{
985+
"cell_type": "code",
986+
"execution_count": null,
987+
"metadata": {},
988+
"outputs": [],
989+
"source": [
990+
"tst = \"\"\"\n",
991+
"# ignored\n",
992+
"{ \"a\":1 }\n",
993+
"hello\n",
994+
"{\n",
995+
"\"b\":2\n",
996+
"}\n",
997+
"\"\"\"\n",
998+
"\n",
999+
"test_eq(list(loads_multi(tst)), [{'a': 1}, {'b': 2}])"
1000+
]
1001+
},
9661002
{
9671003
"cell_type": "code",
9681004
"execution_count": null,
@@ -1840,76 +1876,6 @@
18401876
"for o in 1,True: assert str2bool(o)"
18411877
]
18421878
},
1843-
{
1844-
"cell_type": "code",
1845-
"execution_count": null,
1846-
"metadata": {},
1847-
"outputs": [],
1848-
"source": [
1849-
"#export\n",
1850-
"def _is_instance(f, gs):\n",
1851-
" tst = [g if type(g) in [type, 'function'] else g.__class__ for g in gs]\n",
1852-
" for g in tst:\n",
1853-
" if isinstance(f, g) or f==g: return True\n",
1854-
" return False\n",
1855-
"\n",
1856-
"def _is_first(f, gs):\n",
1857-
" for o in L(getattr(f, 'run_after', None)):\n",
1858-
" if _is_instance(o, gs): return False\n",
1859-
" for g in gs:\n",
1860-
" if _is_instance(f, L(getattr(g, 'run_before', None))): return False\n",
1861-
" return True\n",
1862-
"\n",
1863-
"def sort_by_run(fs):\n",
1864-
" end = L(fs).attrgot('toward_end')\n",
1865-
" inp,res = L(fs)[~end] + L(fs)[end], L()\n",
1866-
" while len(inp):\n",
1867-
" for i,o in enumerate(inp):\n",
1868-
" if _is_first(o, inp):\n",
1869-
" res.append(inp.pop(i))\n",
1870-
" break\n",
1871-
" else: raise Exception(\"Impossible to sort\")\n",
1872-
" return res"
1873-
]
1874-
},
1875-
{
1876-
"cell_type": "markdown",
1877-
"metadata": {},
1878-
"source": [
1879-
"Transforms and callbacks will have run_after/run_before attributes, this function will sort them to respect those requirements (if it's possible). Also, sometimes we want a tranform/callback to be run at the end, but still be able to use run_after/run_before behaviors. For those, the function checks for a toward_end attribute (that needs to be True)."
1880-
]
1881-
},
1882-
{
1883-
"cell_type": "code",
1884-
"execution_count": null,
1885-
"metadata": {},
1886-
"outputs": [],
1887-
"source": [
1888-
"class Tst(): pass \n",
1889-
"class Tst1(): run_before=[Tst]\n",
1890-
"class Tst2():\n",
1891-
" run_before=Tst\n",
1892-
" run_after=Tst1\n",
1893-
" \n",
1894-
"tsts = [Tst(), Tst1(), Tst2()]\n",
1895-
"test_eq(sort_by_run(tsts), [tsts[1], tsts[2], tsts[0]])\n",
1896-
"\n",
1897-
"Tst2.run_before,Tst2.run_after = Tst1,Tst\n",
1898-
"test_fail(lambda: sort_by_run([Tst(), Tst1(), Tst2()]))\n",
1899-
"\n",
1900-
"def tst1(x): return x\n",
1901-
"tst1.run_before = Tst\n",
1902-
"test_eq(sort_by_run([tsts[0], tst1]), [tst1, tsts[0]])\n",
1903-
" \n",
1904-
"class Tst1():\n",
1905-
" toward_end=True\n",
1906-
"class Tst2():\n",
1907-
" toward_end=True\n",
1908-
" run_before=Tst1\n",
1909-
"tsts = [Tst(), Tst1(), Tst2()]\n",
1910-
"test_eq(sort_by_run(tsts), [tsts[0], tsts[2], tsts[1]])"
1911-
]
1912-
},
19131879
{
19141880
"cell_type": "markdown",
19151881
"metadata": {},

0 commit comments

Comments
 (0)