fastcore 2.1.1__tar.gz → 2.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fastcore-2.1.1/fastcore.egg-info → fastcore-2.1.2}/PKG-INFO +1 -1
- fastcore-2.1.2/fastcore/__init__.py +1 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/_modidx.py +25 -1
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/nbio.py +159 -10
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/net.py +39 -2
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/xtras.py +19 -8
- {fastcore-2.1.1 → fastcore-2.1.2/fastcore.egg-info}/PKG-INFO +1 -1
- {fastcore-2.1.1 → fastcore-2.1.2}/pyproject.toml +0 -1
- fastcore-2.1.1/fastcore/__init__.py +0 -1
- {fastcore-2.1.1 → fastcore-2.1.2}/CONTRIBUTING.md +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/LICENSE +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/MANIFEST.in +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/README.md +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/aio.py +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/all.py +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/ansi.py +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/basics.py +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/dispatch.py +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/docments.py +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/docscrape.py +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/foundation.py +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/imghdr.py +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/imports.py +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/meta.py +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/nb_imports.py +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/parallel.py +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/py2pyi.py +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/script.py +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/shutil.py +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/style.py +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/test.py +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/tools.py +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/transform.py +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/utils.py +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/xdg.py +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore/xml.py +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore.egg-info/SOURCES.txt +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore.egg-info/dependency_links.txt +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore.egg-info/entry_points.txt +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore.egg-info/requires.txt +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/fastcore.egg-info/top_level.txt +0 -0
- {fastcore-2.1.1 → fastcore-2.1.2}/setup.cfg +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.1.2"
|
|
@@ -483,7 +483,13 @@ d = { 'settings': { 'branch': 'main',
|
|
|
483
483
|
'fastcore.nbio.NbCell.__eq__': ('nbio.html#nbcell.__eq__', 'fastcore/nbio.py'),
|
|
484
484
|
'fastcore.nbio.NbCell.__hash__': ('nbio.html#nbcell.__hash__', 'fastcore/nbio.py'),
|
|
485
485
|
'fastcore.nbio.NbCell.__init__': ('nbio.html#nbcell.__init__', 'fastcore/nbio.py'),
|
|
486
|
+
'fastcore.nbio.NbCell.__setattr__': ('nbio.html#nbcell.__setattr__', 'fastcore/nbio.py'),
|
|
487
|
+
'fastcore.nbio.NbCell.__setitem__': ('nbio.html#nbcell.__setitem__', 'fastcore/nbio.py'),
|
|
488
|
+
'fastcore.nbio.NbCell._partition': ('nbio.html#nbcell._partition', 'fastcore/nbio.py'),
|
|
489
|
+
'fastcore.nbio.NbCell.directive': ('nbio.html#nbcell.directive', 'fastcore/nbio.py'),
|
|
490
|
+
'fastcore.nbio.NbCell.has_directive': ('nbio.html#nbcell.has_directive', 'fastcore/nbio.py'),
|
|
486
491
|
'fastcore.nbio.NbCell.parsed_': ('nbio.html#nbcell.parsed_', 'fastcore/nbio.py'),
|
|
492
|
+
'fastcore.nbio.NbCell.remove_directives': ('nbio.html#nbcell.remove_directives', 'fastcore/nbio.py'),
|
|
487
493
|
'fastcore.nbio.NbCell.set_source': ('nbio.html#nbcell.set_source', 'fastcore/nbio.py'),
|
|
488
494
|
'fastcore.nbio.Notebook': ('nbio.html#notebook', 'fastcore/nbio.py'),
|
|
489
495
|
'fastcore.nbio.Notebook.__contains__': ('nbio.html#notebook.__contains__', 'fastcore/nbio.py'),
|
|
@@ -506,8 +512,14 @@ d = { 'settings': { 'branch': 'main',
|
|
|
506
512
|
'fastcore.nbio.Notebook.save': ('nbio.html#notebook.save', 'fastcore/nbio.py'),
|
|
507
513
|
'fastcore.nbio.Notebook.view': ('nbio.html#notebook.view', 'fastcore/nbio.py'),
|
|
508
514
|
'fastcore.nbio._dict2obj': ('nbio.html#_dict2obj', 'fastcore/nbio.py'),
|
|
515
|
+
'fastcore.nbio._dir_line': ('nbio.html#_dir_line', 'fastcore/nbio.py'),
|
|
516
|
+
'fastcore.nbio._dir_pre': ('nbio.html#_dir_pre', 'fastcore/nbio.py'),
|
|
517
|
+
'fastcore.nbio._directive': ('nbio.html#_directive', 'fastcore/nbio.py'),
|
|
518
|
+
'fastcore.nbio._directives_get': ('nbio.html#_directives_get', 'fastcore/nbio.py'),
|
|
519
|
+
'fastcore.nbio._directives_set': ('nbio.html#_directives_set', 'fastcore/nbio.py'),
|
|
509
520
|
'fastcore.nbio._is_json_mime': ('nbio.html#_is_json_mime', 'fastcore/nbio.py'),
|
|
510
521
|
'fastcore.nbio._join': ('nbio.html#_join', 'fastcore/nbio.py'),
|
|
522
|
+
'fastcore.nbio._meta_directives': ('nbio.html#_meta_directives', 'fastcore/nbio.py'),
|
|
511
523
|
'fastcore.nbio._mkout': ('nbio.html#_mkout', 'fastcore/nbio.py'),
|
|
512
524
|
'fastcore.nbio._read_json': ('nbio.html#_read_json', 'fastcore/nbio.py'),
|
|
513
525
|
'fastcore.nbio._rejoin_cell': ('nbio.html#_rejoin_cell', 'fastcore/nbio.py'),
|
|
@@ -515,10 +527,12 @@ d = { 'settings': { 'branch': 'main',
|
|
|
515
527
|
'fastcore.nbio._render_text': ('nbio.html#_render_text', 'fastcore/nbio.py'),
|
|
516
528
|
'fastcore.nbio._split_cell': ('nbio.html#_split_cell', 'fastcore/nbio.py'),
|
|
517
529
|
'fastcore.nbio._split_mime': ('nbio.html#_split_mime', 'fastcore/nbio.py'),
|
|
530
|
+
'fastcore.nbio._unparse_dir': ('nbio.html#_unparse_dir', 'fastcore/nbio.py'),
|
|
518
531
|
'fastcore.nbio.cell2xml': ('nbio.html#cell2xml', 'fastcore/nbio.py'),
|
|
519
532
|
'fastcore.nbio.cells2xml': ('nbio.html#cells2xml', 'fastcore/nbio.py'),
|
|
520
533
|
'fastcore.nbio.concat_streams': ('nbio.html#concat_streams', 'fastcore/nbio.py'),
|
|
521
534
|
'fastcore.nbio.dict2nb': ('nbio.html#dict2nb', 'fastcore/nbio.py'),
|
|
535
|
+
'fastcore.nbio.first_code_ln': ('nbio.html#first_code_ln', 'fastcore/nbio.py'),
|
|
522
536
|
'fastcore.nbio.mk_cell': ('nbio.html#mk_cell', 'fastcore/nbio.py'),
|
|
523
537
|
'fastcore.nbio.mk_display': ('nbio.html#mk_display', 'fastcore/nbio.py'),
|
|
524
538
|
'fastcore.nbio.mk_error': ('nbio.html#mk_error', 'fastcore/nbio.py'),
|
|
@@ -526,6 +540,7 @@ d = { 'settings': { 'branch': 'main',
|
|
|
526
540
|
'fastcore.nbio.mk_stream': ('nbio.html#mk_stream', 'fastcore/nbio.py'),
|
|
527
541
|
'fastcore.nbio.nb2dict': ('nbio.html#nb2dict', 'fastcore/nbio.py'),
|
|
528
542
|
'fastcore.nbio.nb2str': ('nbio.html#nb2str', 'fastcore/nbio.py'),
|
|
543
|
+
'fastcore.nbio.nb_lang': ('nbio.html#nb_lang', 'fastcore/nbio.py'),
|
|
529
544
|
'fastcore.nbio.new_nb': ('nbio.html#new_nb', 'fastcore/nbio.py'),
|
|
530
545
|
'fastcore.nbio.preferred_msg_out': ('nbio.html#preferred_msg_out', 'fastcore/nbio.py'),
|
|
531
546
|
'fastcore.nbio.preferred_out': ('nbio.html#preferred_out', 'fastcore/nbio.py'),
|
|
@@ -533,6 +548,8 @@ d = { 'settings': { 'branch': 'main',
|
|
|
533
548
|
'fastcore.nbio.render_output': ('nbio.html#render_output', 'fastcore/nbio.py'),
|
|
534
549
|
'fastcore.nbio.render_outputs': ('nbio.html#render_outputs', 'fastcore/nbio.py'),
|
|
535
550
|
'fastcore.nbio.render_text': ('nbio.html#render_text', 'fastcore/nbio.py'),
|
|
551
|
+
'fastcore.nbio.repair_cell': ('nbio.html#repair_cell', 'fastcore/nbio.py'),
|
|
552
|
+
'fastcore.nbio.repair_nb': ('nbio.html#repair_nb', 'fastcore/nbio.py'),
|
|
536
553
|
'fastcore.nbio.validate_cell': ('nbio.html#validate_cell', 'fastcore/nbio.py'),
|
|
537
554
|
'fastcore.nbio.validate_nb': ('nbio.html#validate_nb', 'fastcore/nbio.py'),
|
|
538
555
|
'fastcore.nbio.write_nb': ('nbio.html#write_nb', 'fastcore/nbio.py')},
|
|
@@ -542,7 +559,9 @@ d = { 'settings': { 'branch': 'main',
|
|
|
542
559
|
'fastcore.net._SafeRedirectHandler.redirect_request': ( 'net.html#_saferedirecthandler.redirect_request',
|
|
543
560
|
'fastcore/net.py'),
|
|
544
561
|
'fastcore.net._socket_det': ('net.html#_socket_det', 'fastcore/net.py'),
|
|
562
|
+
'fastcore.net._waitfor': ('net.html#_waitfor', 'fastcore/net.py'),
|
|
545
563
|
'fastcore.net.http_response': ('net.html#http_response', 'fastcore/net.py'),
|
|
564
|
+
'fastcore.net.is_port_free': ('net.html#is_port_free', 'fastcore/net.py'),
|
|
546
565
|
'fastcore.net.recv_once': ('net.html#recv_once', 'fastcore/net.py'),
|
|
547
566
|
'fastcore.net.start_client': ('net.html#start_client', 'fastcore/net.py'),
|
|
548
567
|
'fastcore.net.start_server': ('net.html#start_server', 'fastcore/net.py'),
|
|
@@ -557,7 +576,11 @@ d = { 'settings': { 'branch': 'main',
|
|
|
557
576
|
'fastcore.net.urlretrieve': ('net.html#urlretrieve', 'fastcore/net.py'),
|
|
558
577
|
'fastcore.net.urlsave': ('net.html#urlsave', 'fastcore/net.py'),
|
|
559
578
|
'fastcore.net.urlvalid': ('net.html#urlvalid', 'fastcore/net.py'),
|
|
560
|
-
'fastcore.net.urlwrap': ('net.html#urlwrap', 'fastcore/net.py')
|
|
579
|
+
'fastcore.net.urlwrap': ('net.html#urlwrap', 'fastcore/net.py'),
|
|
580
|
+
'fastcore.net.wait_port_free': ('net.html#wait_port_free', 'fastcore/net.py'),
|
|
581
|
+
'fastcore.net.wait_port_free_async': ('net.html#wait_port_free_async', 'fastcore/net.py'),
|
|
582
|
+
'fastcore.net.waitfor': ('net.html#waitfor', 'fastcore/net.py'),
|
|
583
|
+
'fastcore.net.waitfor_async': ('net.html#waitfor_async', 'fastcore/net.py')},
|
|
561
584
|
'fastcore.parallel': { 'fastcore.parallel.ProcessPoolExecutor': ('parallel.html#processpoolexecutor', 'fastcore/parallel.py'),
|
|
562
585
|
'fastcore.parallel.ProcessPoolExecutor.__init__': ( 'parallel.html#processpoolexecutor.__init__',
|
|
563
586
|
'fastcore/parallel.py'),
|
|
@@ -852,6 +875,7 @@ d = { 'settings': { 'branch': 'main',
|
|
|
852
875
|
'fastcore.xtras.ssh': ('xtras.html#ssh', 'fastcore/xtras.py'),
|
|
853
876
|
'fastcore.xtras.str_diff': ('xtras.html#str_diff', 'fastcore/xtras.py'),
|
|
854
877
|
'fastcore.xtras.stringfmt_names': ('xtras.html#stringfmt_names', 'fastcore/xtras.py'),
|
|
878
|
+
'fastcore.xtras.take_lines': ('xtras.html#take_lines', 'fastcore/xtras.py'),
|
|
855
879
|
'fastcore.xtras.time_policy': ('xtras.html#time_policy', 'fastcore/xtras.py'),
|
|
856
880
|
'fastcore.xtras.timed_cache': ('xtras.html#timed_cache', 'fastcore/xtras.py'),
|
|
857
881
|
'fastcore.xtras.trace': ('xtras.html#trace', 'fastcore/xtras.py'),
|
|
@@ -5,18 +5,20 @@ Docs: https://fastcore.fast.ai/nbio.html.md"""
|
|
|
5
5
|
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/13_nbio.ipynb.
|
|
6
6
|
|
|
7
7
|
# %% auto #0
|
|
8
|
-
__all__ = ['
|
|
9
|
-
'
|
|
10
|
-
'
|
|
8
|
+
__all__ = ['langs', 'nb_lang', 'NbCell', 'dict2nb', 'read_nb', 'mk_cell', 'new_nb', 'first_code_ln', 'nb2dict', 'nb2str',
|
|
9
|
+
'write_nb', 'validate_cell', 'validate_nb', 'repair_cell', 'repair_nb', 'preferred_out', 'mk_stream',
|
|
10
|
+
'mk_result', 'mk_display', 'mk_error', 'concat_streams', 'preferred_msg_out', 'render_output',
|
|
11
|
+
'render_outputs', 'render_text', 'cell2xml', 'cells2xml', 'Notebook']
|
|
11
12
|
|
|
12
13
|
# %% ../nbs/13_nbio.ipynb #954ca1aa
|
|
13
14
|
from .basics import *
|
|
14
|
-
from .xtras import rtoken_hex,clean_cli_output
|
|
15
|
+
from .xtras import rtoken_hex,clean_cli_output,take_lines
|
|
15
16
|
from .imports import *
|
|
16
17
|
from .ansi import ansi2html
|
|
17
18
|
from .meta import delegates
|
|
18
19
|
|
|
19
20
|
import ast,functools
|
|
21
|
+
from collections import defaultdict
|
|
20
22
|
from pprint import pformat,pprint
|
|
21
23
|
from json import loads,dumps
|
|
22
24
|
|
|
@@ -42,18 +44,39 @@ def _rejoin_cell(c):
|
|
|
42
44
|
if o.get('output_type') in ('execute_result','display_data'): _rejoin_mime(o.get('data', {}))
|
|
43
45
|
elif o.get('output_type')=='stream' and isinstance(o.get('text'), list): o['text'] = ''.join(o['text'])
|
|
44
46
|
|
|
47
|
+
# %% ../nbs/13_nbio.ipynb #e13f61b8
|
|
48
|
+
# from https://github.com/quarto-dev/quarto-cli/blob/main/src/resources/jupyter/notebook.py
|
|
49
|
+
langs = defaultdict(
|
|
50
|
+
lambda: '#', r = "#", python = "#", julia = "#", scala = "//", matlab = "%", csharp = "//", fsharp = "//",
|
|
51
|
+
c = ["/*","*/"], css = ["/*","*/"], sas = ["*",";"], powershell = "#", bash = "#", sql = "--", mysql = "--", psql = "--",
|
|
52
|
+
lua = "--", cpp = "//", cc = "//", stan = "#", octave = "#", fortran = "!", fortran95 = "!", awk = "#", gawk = "#", stata = "*",
|
|
53
|
+
java = "//", groovy = "//", sed = "#", perl = "#", ruby = "#", tikz = "%", javascript = "//", js = "//", d3 = "//", node = "//",
|
|
54
|
+
sass = "//", coffee = "#", go = "//", asy = "//", haskell = "--", dot = "//", apl = "⍝")
|
|
55
|
+
|
|
56
|
+
def nb_lang(nb): return nested_attr(nb, 'metadata.kernelspec.language', 'python')
|
|
57
|
+
|
|
45
58
|
# %% ../nbs/13_nbio.ipynb #49d7bf89
|
|
46
59
|
class NbCell(AttrDict):
|
|
47
|
-
def __init__(self, idx, cell):
|
|
60
|
+
def __init__(self, idx, cell, lang='python'):
|
|
48
61
|
super().__init__(cell)
|
|
49
62
|
self.idx_ = idx
|
|
63
|
+
self.lang_ = nested_attr(self, 'metadata.language', lang)
|
|
50
64
|
if 'id' not in self: self.id = rtoken_hex(4)
|
|
51
65
|
if 'source' in self: self.set_source(self.source)
|
|
52
66
|
_rejoin_cell(self)
|
|
53
67
|
|
|
54
|
-
def
|
|
55
|
-
|
|
56
|
-
if
|
|
68
|
+
def __setattr__(self, k, v):
|
|
69
|
+
prop = getattr(type(self), k, None)
|
|
70
|
+
if isinstance(prop, property) and prop.fset: prop.fset(self, v)
|
|
71
|
+
else: super().__setattr__(k, v)
|
|
72
|
+
|
|
73
|
+
def __setitem__(self, k, v):
|
|
74
|
+
super().__setitem__(k, v)
|
|
75
|
+
if k in ('source','metadata'):
|
|
76
|
+
for c in ('_parsed_','_directives_','_meta_names_'):
|
|
77
|
+
if c in self: del(self[c])
|
|
78
|
+
|
|
79
|
+
def set_source(self, source): self.source = ''.join(source)
|
|
57
80
|
|
|
58
81
|
def parsed_(self):
|
|
59
82
|
if self.cell_type!='code' or self.source.strip()[:1] in ['%', '!']: return
|
|
@@ -77,7 +100,7 @@ def _dict2obj(d, list_func=list, dict_func=AttrDict):
|
|
|
77
100
|
def dict2nb(js=None, **kwargs):
|
|
78
101
|
"Convert dict `js` to an `AttrDict`, "
|
|
79
102
|
nb = _dict2obj(js or kwargs)
|
|
80
|
-
nb.cells = [NbCell(
|
|
103
|
+
nb.cells = [NbCell(i, o, nb_lang(nb)) for i,o in enumerate(nb.cells)]
|
|
81
104
|
return nb
|
|
82
105
|
|
|
83
106
|
# %% ../nbs/13_nbio.ipynb #0626f06e
|
|
@@ -104,9 +127,94 @@ def mk_cell(
|
|
|
104
127
|
# %% ../nbs/13_nbio.ipynb #e7af3290
|
|
105
128
|
def new_nb(cells=None, meta=None, nbformat=4, nbformat_minor=5):
|
|
106
129
|
"Returns an empty new notebook"
|
|
107
|
-
cells = [o if isinstance(o,dict) else mk_cell(o) for o in cells]
|
|
130
|
+
cells = [o if isinstance(o,dict) else mk_cell(o) for o in cells or []]
|
|
108
131
|
return dict2nb(cells=cells or [],metadata=meta or {},nbformat=nbformat,nbformat_minor=nbformat_minor)
|
|
109
132
|
|
|
133
|
+
# %% ../nbs/13_nbio.ipynb #c2ed0d5e
|
|
134
|
+
def _dir_pre(lang=None): return fr"\s*{langs[lang]}\s*\|"
|
|
135
|
+
_cell_mgc = re.compile(r"^\s*%%\w+")
|
|
136
|
+
|
|
137
|
+
def first_code_ln(code_list, re_pattern=None, lang='python'):
|
|
138
|
+
"get first line number where code occurs, where `code_list` is a list of code"
|
|
139
|
+
if re_pattern is None: re_pattern = _dir_pre(lang)
|
|
140
|
+
return first(i for i,o in enumerate(code_list) if o.strip() != '' and not re.match(re_pattern, o) and not _cell_mgc.match(o))
|
|
141
|
+
|
|
142
|
+
# %% ../nbs/13_nbio.ipynb #b0cc33c0
|
|
143
|
+
def _directive(s, lang='python'):
|
|
144
|
+
"Parse a directive line into `(name, value)`; None if `s` is not a directive line"
|
|
145
|
+
if not re.match(_dir_pre(lang), s): return None
|
|
146
|
+
s = re.sub('^'+_dir_pre(lang), '', s).strip()
|
|
147
|
+
m = re.match(r'([^\s:]+)\s*:?\s?(.*?)\s*$', s, flags=re.S)
|
|
148
|
+
if not m: return None
|
|
149
|
+
name,v = m.groups()
|
|
150
|
+
return name, ('' if v=='true' else v)
|
|
151
|
+
|
|
152
|
+
# %% ../nbs/13_nbio.ipynb #16c08410
|
|
153
|
+
def _meta_directives(cell):
|
|
154
|
+
"Directives from the `nbdev` dict in cell metadata, as `{name: value}`"
|
|
155
|
+
def _v(v):
|
|
156
|
+
if isinstance(v,bool): return '' if v else 'false'
|
|
157
|
+
if isinstance(v,(list,tuple)): return ' '.join(map(str,v))
|
|
158
|
+
return '' if v=='true' else str(v)
|
|
159
|
+
return {k:_v(v) for k,v in cell.get('metadata',{}).get('nbdev',{}).items()}
|
|
160
|
+
|
|
161
|
+
def _unparse_dir(v):
|
|
162
|
+
"Inverse of `_meta_directives` value parsing: value string back to a metadata value"
|
|
163
|
+
if v=='': return True
|
|
164
|
+
if v=='false': return False
|
|
165
|
+
return v
|
|
166
|
+
|
|
167
|
+
def _dir_line(k, v, lang='python', quarto=False):
|
|
168
|
+
"A canonical directive comment line; with `quarto`, bare directives render as `: true`"
|
|
169
|
+
if quarto and not v: v = 'true'
|
|
170
|
+
return f"{langs[lang]}| {k}" + (f": {v}" if v else '') + '\n'
|
|
171
|
+
|
|
172
|
+
# %% ../nbs/13_nbio.ipynb #428ecb6a
|
|
173
|
+
@patch
|
|
174
|
+
def _partition(self:NbCell):
|
|
175
|
+
"Split source into leading directive lines (with magics and blanks) and the rest"
|
|
176
|
+
dirs = take_lines(self.source, fr'^({_dir_pre(self.lang_)}|\s*%%\w+|\s*$)')
|
|
177
|
+
return dirs.splitlines(True), self.source[len(dirs):].splitlines(True)
|
|
178
|
+
|
|
179
|
+
def _directives_get(self):
|
|
180
|
+
"Directives from leading comments and the metadata `nbdev` key; comments win. Assign a modified copy back to update the cell."
|
|
181
|
+
if '_directives_' not in self:
|
|
182
|
+
dirs,_ = self._partition()
|
|
183
|
+
cmts = dict(t for t in (_directive(s, self.lang_) for s in dirs) if t)
|
|
184
|
+
meta = _meta_directives(self)
|
|
185
|
+
self['_meta_names_'] = set(meta) - set(cmts)
|
|
186
|
+
self['_directives_'] = cmts | {k:v for k,v in meta.items() if k not in cmts}
|
|
187
|
+
return dict(self['_directives_'])
|
|
188
|
+
|
|
189
|
+
def _directives_set(self, d):
|
|
190
|
+
if d == self.directives: return
|
|
191
|
+
mnames = self['_meta_names_']
|
|
192
|
+
meta = {k:_unparse_dir(v) for k,v in d.items() if k in mnames}
|
|
193
|
+
lines = [_dir_line(k, v, self.lang_) for k,v in d.items() if k not in mnames]
|
|
194
|
+
if meta: self.setdefault('metadata', AttrDict())['nbdev'] = meta
|
|
195
|
+
elif 'nbdev' in self.get('metadata', {}): del self.metadata['nbdev']
|
|
196
|
+
dirs,code = self._partition()
|
|
197
|
+
self.set_source(''.join([o for o in dirs if _cell_mgc.match(o)] + lines + code))
|
|
198
|
+
|
|
199
|
+
NbCell.directives = property(_directives_get, _directives_set)
|
|
200
|
+
|
|
201
|
+
# %% ../nbs/13_nbio.ipynb #281f7f8a
|
|
202
|
+
@patch
|
|
203
|
+
def directive(self:NbCell, name, default=None):
|
|
204
|
+
"Value of directive `name` (`''` if bare), or `default` if absent"
|
|
205
|
+
return self.directives.get(name, default)
|
|
206
|
+
|
|
207
|
+
@patch
|
|
208
|
+
def has_directive(self:NbCell, name): return self.directive(name) is not None
|
|
209
|
+
|
|
210
|
+
@patch
|
|
211
|
+
def remove_directives(self:NbCell, quarto=False):
|
|
212
|
+
"Strip directives from source, keeping cell magics; with `quarto`, instead materialize every directive (metadata included) as a Quarto option line"
|
|
213
|
+
dirs,code = self._partition()
|
|
214
|
+
keep = [o for o in dirs if _cell_mgc.match(o)]
|
|
215
|
+
if quarto: keep += [_dir_line(k, v, self.lang_, quarto=True) for k,v in self.directives.items()]
|
|
216
|
+
self.set_source(''.join(keep + code))
|
|
217
|
+
|
|
110
218
|
# %% ../nbs/13_nbio.ipynb #7c7bab22
|
|
111
219
|
def _split_mime(data):
|
|
112
220
|
"Copy of mimebundle `data` with multiline text split to lists of lines, like nbformat's `split_lines`"
|
|
@@ -171,6 +279,47 @@ def validate_nb(nb):
|
|
|
171
279
|
if dups := {o for o in ids if ids.count(o)>1}: raise ValueError(f"duplicate cell id(s): {', '.join(sorted(dups))}")
|
|
172
280
|
return nb
|
|
173
281
|
|
|
282
|
+
# %% ../nbs/13_nbio.ipynb #d38902eb
|
|
283
|
+
def repair_cell(cell, idx=None):
|
|
284
|
+
"Fix deterministic structural problems in `cell`, returning a list of repairs made"
|
|
285
|
+
res,where = [],f"cell {cell.get('id', idx)}"
|
|
286
|
+
src = cell.get('source', '')
|
|
287
|
+
if not (isinstance(src,str) or (isinstance(src,list) and all(isinstance(o,str) for o in src))):
|
|
288
|
+
cell['source'] = ''.join(map(str, listify(src)))
|
|
289
|
+
res.append(f"{where}: coerced source to text")
|
|
290
|
+
if not isinstance(cell.get('metadata', {}), dict):
|
|
291
|
+
cell['metadata'] = {}
|
|
292
|
+
res.append(f"{where}: reset non-dict metadata")
|
|
293
|
+
if cell.get('cell_type')=='code':
|
|
294
|
+
if not isinstance(cell.get('outputs'), list):
|
|
295
|
+
cell['outputs'] = []
|
|
296
|
+
res.append(f"{where}: added outputs list")
|
|
297
|
+
if 'execution_count' not in cell:
|
|
298
|
+
cell['execution_count'] = None
|
|
299
|
+
res.append(f"{where}: added execution_count")
|
|
300
|
+
else:
|
|
301
|
+
for k in ('outputs','execution_count'):
|
|
302
|
+
if k in cell:
|
|
303
|
+
del cell[k]
|
|
304
|
+
res.append(f"{where}: removed {k}")
|
|
305
|
+
return res
|
|
306
|
+
|
|
307
|
+
def repair_nb(nb):
|
|
308
|
+
"Fix deterministic structural problems in `nb`, returning a list of repairs made"
|
|
309
|
+
res = []
|
|
310
|
+
for k,v in dict(cells=[], metadata={}, nbformat=4).items():
|
|
311
|
+
if k not in nb:
|
|
312
|
+
nb[k] = v
|
|
313
|
+
res.append(f"added notebook {k}")
|
|
314
|
+
for i,c in enumerate(nb['cells']): res += repair_cell(c, i)
|
|
315
|
+
seen = set()
|
|
316
|
+
for c in nb['cells']:
|
|
317
|
+
if (i := c.get('id')) in seen:
|
|
318
|
+
c['id'] = rtoken_hex(4)
|
|
319
|
+
res.append(f"cell {i}: duplicate id, regenerated as {c['id']}")
|
|
320
|
+
seen.add(c.get('id'))
|
|
321
|
+
return res
|
|
322
|
+
|
|
174
323
|
# %% ../nbs/13_nbio.ipynb #530b9cd1
|
|
175
324
|
from .xml import NB,to_xml,ft,item2xml
|
|
176
325
|
|
|
@@ -7,7 +7,8 @@ Docs: https://fastcore.fast.ai/net.html.md"""
|
|
|
7
7
|
# %% auto #0
|
|
8
8
|
__all__ = ['url_default_headers', 'ExceptionsHTTP', 'urlquote', 'urlwrap', 'HTTP4xxClientError', 'HTTP5xxServerError',
|
|
9
9
|
'urlopener', 'urlopen', 'urlread', 'urljson', 'urlclean', 'urlretrieve', 'urldest', 'urlsave', 'urlvalid',
|
|
10
|
-
'start_server', 'start_client', 'tobytes', 'http_response', 'recv_once', '
|
|
10
|
+
'start_server', 'start_client', 'tobytes', 'http_response', 'recv_once', 'waitfor', 'waitfor_async',
|
|
11
|
+
'is_port_free', 'wait_port_free', 'wait_port_free_async', 'HTTP400BadRequestError',
|
|
11
12
|
'HTTP401UnauthorizedError', 'HTTP402PaymentRequiredError', 'HTTP403ForbiddenError', 'HTTP404NotFoundError',
|
|
12
13
|
'HTTP405MethodNotAllowedError', 'HTTP406NotAcceptableError', 'HTTP407ProxyAuthRequiredError',
|
|
13
14
|
'HTTP408RequestTimeoutError', 'HTTP409ConflictError', 'HTTP410GoneError', 'HTTP411LengthRequiredError',
|
|
@@ -23,7 +24,7 @@ from .utils import *
|
|
|
23
24
|
from .parallel import *
|
|
24
25
|
|
|
25
26
|
import json,urllib,contextlib,tempfile
|
|
26
|
-
import socket,urllib.request,urllib,asyncio,threading
|
|
27
|
+
import socket,urllib.request,urllib,asyncio,threading,time
|
|
27
28
|
from contextlib import contextmanager
|
|
28
29
|
from urllib.request import Request,urlretrieve
|
|
29
30
|
from urllib.error import HTTPError,URLError
|
|
@@ -240,3 +241,39 @@ def recv_once(host:str='localhost', port:int=8000):
|
|
|
240
241
|
res = conn.recv(1024)
|
|
241
242
|
conn.sendall(http_response(res))
|
|
242
243
|
return res
|
|
244
|
+
|
|
245
|
+
# %% ../nbs/03b_net.ipynb #8896fe36
|
|
246
|
+
def _waitfor(f, timeout, msg):
|
|
247
|
+
end = time.time()+timeout
|
|
248
|
+
while not f():
|
|
249
|
+
if time.time()>end: raise TimeoutError(msg or f"Timeout after {timeout}s")
|
|
250
|
+
yield 0.1
|
|
251
|
+
|
|
252
|
+
def waitfor(f, timeout=20, msg=None):
|
|
253
|
+
"Call `f` every 0.1s until it returns truthy, raising `TimeoutError` with `msg` after `timeout` secs"
|
|
254
|
+
for d in _waitfor(f, timeout, msg): time.sleep(d)
|
|
255
|
+
|
|
256
|
+
async def waitfor_async(f, timeout=20, msg=None):
|
|
257
|
+
"Async version of `waitfor`"
|
|
258
|
+
for d in _waitfor(f, timeout, msg): await asyncio.sleep(d)
|
|
259
|
+
|
|
260
|
+
# %% ../nbs/03b_net.ipynb #38a94895
|
|
261
|
+
def is_port_free(port, host='localhost'):
|
|
262
|
+
"Is `port` free on `host`?"
|
|
263
|
+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
264
|
+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
265
|
+
try:
|
|
266
|
+
sock.bind((host,port))
|
|
267
|
+
sock.listen(1)
|
|
268
|
+
return True
|
|
269
|
+
except OSError: return False
|
|
270
|
+
finally: sock.close()
|
|
271
|
+
|
|
272
|
+
# %% ../nbs/03b_net.ipynb #e0a7369a
|
|
273
|
+
def wait_port_free(port, host='localhost', max_wait=20):
|
|
274
|
+
"Wait for `port` to be free on `host`"
|
|
275
|
+
waitfor(partial(is_port_free, port, host), max_wait, f"Port {host}:{port} not free after {max_wait}s")
|
|
276
|
+
|
|
277
|
+
async def wait_port_free_async(port, host='localhost', max_wait=20):
|
|
278
|
+
"Async wait for `port` to be free on `host`"
|
|
279
|
+
await waitfor_async(partial(is_port_free, port, host), max_wait, f"Port {host}:{port} not free after {max_wait}s")
|
|
@@ -9,14 +9,14 @@ __all__ = ['UNSET', 'spark_chars', 'walk_join', 'walk', 'exttypes', 'globtastic'
|
|
|
9
9
|
'img_bytes', 'detect_mime', 'bunzip', 'loads', 'loads_multi', 'dumps', 'untar_dir', 'repo_details', 'shell',
|
|
10
10
|
'ssh', 'rsync_multi', 'run', 'open_file', 'save_pickle', 'load_pickle', 'parse_env', 'expand_wildcards',
|
|
11
11
|
'atomic_save', 'load_mod', 'import_no_init', 'save_config_file', 'read_config_file', 'find_file_parents',
|
|
12
|
-
'Config', 'Unset', 'dict2obj', 'obj2dict', 'repr_dict', 'is_listy', 'mapped', '
|
|
13
|
-
'SaveReturn', 'trim_wraps', 'save_iter', 'asave_iter', 'frontmatter',
|
|
14
|
-
'
|
|
15
|
-
'
|
|
16
|
-
'
|
|
17
|
-
'trace', 'modified_env', 'ContextManagers', 'shufflish', 'console_help', 'hl_md',
|
|
18
|
-
'dataclass_src', 'nullable_dc', 'make_nullable', 'flexiclass', 'asdict', 'vars_pub',
|
|
19
|
-
'is_namedtuple', 'CachedIter', 'flexicache', 'time_policy', 'mtime_policy', 'timed_cache']
|
|
12
|
+
'Config', 'Unset', 'dict2obj', 'obj2dict', 'repr_dict', 'is_listy', 'mapped', 'take_lines', 'IterLen',
|
|
13
|
+
'ReindexCollection', 'SaveReturn', 'trim_wraps', 'save_iter', 'asave_iter', 'frontmatter',
|
|
14
|
+
'clean_cli_output', 'unqid', 'rtoken_hex', 'friendly_name', 'n_friendly_names', 'exec_eval',
|
|
15
|
+
'get_source_link', 'sparkline', 'modify_exception', 'round_multiple', 'set_num_threads', 'join_path_file',
|
|
16
|
+
'autostart', 'EventTimer', 'stringfmt_names', 'PartialFormatter', 'partial_format', 'truncstr', 'str_diff',
|
|
17
|
+
'utc2local', 'local2utc', 'trace', 'modified_env', 'ContextManagers', 'shufflish', 'console_help', 'hl_md',
|
|
18
|
+
'type2str', 'dataclass_src', 'nullable_dc', 'make_nullable', 'flexiclass', 'asdict', 'vars_pub',
|
|
19
|
+
'is_typeddict', 'is_namedtuple', 'CachedIter', 'flexicache', 'time_policy', 'mtime_policy', 'timed_cache']
|
|
20
20
|
|
|
21
21
|
# %% ../nbs/03_xtras.ipynb #3401d507
|
|
22
22
|
from .imports import *
|
|
@@ -562,6 +562,17 @@ def mapped(f, it):
|
|
|
562
562
|
"map `f` over `it`, unless it's not listy, in which case return `f(it)`"
|
|
563
563
|
return L(it).map(f) if is_listy(it) else f(it)
|
|
564
564
|
|
|
565
|
+
# %% ../nbs/03_xtras.ipynb #062ca713
|
|
566
|
+
def take_lines(s, pat, atstart=True, atend=False, drop=False):
|
|
567
|
+
"Take contiguous lines matching `pat` from either end of `s`"
|
|
568
|
+
ls,pred = s.splitlines(keepends=True),re.compile(pat).search
|
|
569
|
+
i,j = 0,len(ls)
|
|
570
|
+
if atstart:
|
|
571
|
+
while i<j and pred(ls[i]): i += 1
|
|
572
|
+
if atend:
|
|
573
|
+
while i<j and pred(ls[j-1]): j -= 1
|
|
574
|
+
return ''.join(ls[i:j] if drop else ls[:i]+ls[j:])
|
|
575
|
+
|
|
565
576
|
# %% ../nbs/03_xtras.ipynb #ab0758e6
|
|
566
577
|
@patch
|
|
567
578
|
def readlines(self:Path, hint=-1, encoding='utf8'):
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "2.1.1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|