fastcore 2.2.23__tar.gz → 2.2.25__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.2.23/fastcore.egg-info → fastcore-2.2.25}/PKG-INFO +2 -1
- {fastcore-2.2.23 → fastcore-2.2.25}/README.md +1 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/__init__.py +2 -2
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/_modidx.py +19 -1
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/script.py +4 -1
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/xml.py +146 -5
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/xtras.py +6 -11
- {fastcore-2.2.23 → fastcore-2.2.25/fastcore.egg-info}/PKG-INFO +2 -1
- {fastcore-2.2.23 → fastcore-2.2.25}/CONTRIBUTING.md +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/LICENSE +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/aio.py +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/all.py +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/ansi.py +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/apisurface.py +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/basics.py +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/dispatch.py +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/docments.py +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/docscrape.py +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/editskill.py +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/foundation.py +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/funccall.py +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/imghdr.py +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/imports.py +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/meta.py +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/nb_imports.py +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/nbio.py +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/net.py +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/parallel.py +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/py2pyi.py +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/shutil.py +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/style.py +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/test.py +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/tools.py +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/transform.py +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/utils.py +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore/xdg.py +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore.egg-info/SOURCES.txt +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore.egg-info/dependency_links.txt +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore.egg-info/entry_points.txt +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore.egg-info/requires.txt +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/fastcore.egg-info/top_level.txt +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/pyproject.toml +0 -0
- {fastcore-2.2.23 → fastcore-2.2.25}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastcore
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.25
|
|
4
4
|
Summary: Python supercharged for fastai development
|
|
5
5
|
Author-email: Jeremy Howard and Sylvain Gugger <infos@fast.ai>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -84,6 +84,7 @@ To install fastcore run: `conda install fastcore -c fastai` (if you use Anaconda
|
|
|
84
84
|
- `fastcore.test`: Simple testing functions
|
|
85
85
|
- `fastcore.foundation`: Mixins, delegation, composition, and more
|
|
86
86
|
- `fastcore.xtras`: Utility functions to help with functional-style programming, parallel processing, and more
|
|
87
|
+
- `fastcore.xml`: HTML with [`ft`](https://fastcore.fast.ai/xml.html#ft), and case-preserving, namespace-aware XML with [`E`](https://fastcore.fast.ai/xml.html#e) factories
|
|
87
88
|
|
|
88
89
|
To get started, we recommend you read through [the fastcore tour](https://fastcore.fast.ai/tour.html).
|
|
89
90
|
|
|
@@ -53,6 +53,7 @@ To install fastcore run: `conda install fastcore -c fastai` (if you use Anaconda
|
|
|
53
53
|
- `fastcore.test`: Simple testing functions
|
|
54
54
|
- `fastcore.foundation`: Mixins, delegation, composition, and more
|
|
55
55
|
- `fastcore.xtras`: Utility functions to help with functional-style programming, parallel processing, and more
|
|
56
|
+
- `fastcore.xml`: HTML with [`ft`](https://fastcore.fast.ai/xml.html#ft), and case-preserving, namespace-aware XML with [`E`](https://fastcore.fast.ai/xml.html#e) factories
|
|
56
57
|
|
|
57
58
|
To get started, we recommend you read through [the fastcore tour](https://fastcore.fast.ai/tour.html).
|
|
58
59
|
|
|
@@ -52,7 +52,7 @@ Modules:
|
|
|
52
52
|
- `fastcore.test`: Helper functions to quickly write tests in notebooks
|
|
53
53
|
- `fastcore.tools`: Text and file editing primitives shared by the fastai editing tools
|
|
54
54
|
- `fastcore.xdg`: XDG Base Directory Specification helpers.
|
|
55
|
-
- `fastcore.xml`: Concise generation
|
|
55
|
+
- `fastcore.xml`: Concise HTML generation and namespace-aware XML construction.
|
|
56
56
|
- `fastcore.xtras`: Utility functions used in the fastai library"""
|
|
57
57
|
|
|
58
|
-
__version__ = "2.2.
|
|
58
|
+
__version__ = "2.2.25"
|
|
@@ -812,7 +812,12 @@ d = { 'settings': { 'branch': 'main',
|
|
|
812
812
|
'fastcore.xdg.xdg_data_home': ('xdg.html#xdg_data_home', 'fastcore/xdg.py'),
|
|
813
813
|
'fastcore.xdg.xdg_runtime_dir': ('xdg.html#xdg_runtime_dir', 'fastcore/xdg.py'),
|
|
814
814
|
'fastcore.xdg.xdg_state_home': ('xdg.html#xdg_state_home', 'fastcore/xdg.py')},
|
|
815
|
-
'fastcore.xml': { 'fastcore.xml.
|
|
815
|
+
'fastcore.xml': { 'fastcore.xml.E': ('xml.html#e', 'fastcore/xml.py'),
|
|
816
|
+
'fastcore.xml.E.__call__': ('xml.html#e.__call__', 'fastcore/xml.py'),
|
|
817
|
+
'fastcore.xml.E.__getattr__': ('xml.html#e.__getattr__', 'fastcore/xml.py'),
|
|
818
|
+
'fastcore.xml.E.__init__': ('xml.html#e.__init__', 'fastcore/xml.py'),
|
|
819
|
+
'fastcore.xml.E._namespace': ('xml.html#e._namespace', 'fastcore/xml.py'),
|
|
820
|
+
'fastcore.xml.FT': ('xml.html#ft', 'fastcore/xml.py'),
|
|
816
821
|
'fastcore.xml.FT.__call__': ('xml.html#ft.__call__', 'fastcore/xml.py'),
|
|
817
822
|
'fastcore.xml.FT.__eq__': ('xml.html#ft.__eq__', 'fastcore/xml.py'),
|
|
818
823
|
'fastcore.xml.FT.__getattr__': ('xml.html#ft.__getattr__', 'fastcore/xml.py'),
|
|
@@ -833,6 +838,14 @@ d = { 'settings': { 'branch': 'main',
|
|
|
833
838
|
'fastcore.xml.Html': ('xml.html#html', 'fastcore/xml.py'),
|
|
834
839
|
'fastcore.xml.Safe': ('xml.html#safe', 'fastcore/xml.py'),
|
|
835
840
|
'fastcore.xml.Safe.__html__': ('xml.html#safe.__html__', 'fastcore/xml.py'),
|
|
841
|
+
'fastcore.xml.XML': ('xml.html#xml', 'fastcore/xml.py'),
|
|
842
|
+
'fastcore.xml.XML.__call__': ('xml.html#xml.__call__', 'fastcore/xml.py'),
|
|
843
|
+
'fastcore.xml.XML.__init__': ('xml.html#xml.__init__', 'fastcore/xml.py'),
|
|
844
|
+
'fastcore.xml.XML.__str__': ('xml.html#xml.__str__', 'fastcore/xml.py'),
|
|
845
|
+
'fastcore.xml.XML._child': ('xml.html#xml._child', 'fastcore/xml.py'),
|
|
846
|
+
'fastcore.xml.XML._render': ('xml.html#xml._render', 'fastcore/xml.py'),
|
|
847
|
+
'fastcore.xml.XML._repr_markdown_': ('xml.html#xml._repr_markdown_', 'fastcore/xml.py'),
|
|
848
|
+
'fastcore.xml.XML.bytes': ('xml.html#xml.bytes', 'fastcore/xml.py'),
|
|
836
849
|
'fastcore.xml._attr2tag': ('xml.html#_attr2tag', 'fastcore/xml.py'),
|
|
837
850
|
'fastcore.xml._escape': ('xml.html#_escape', 'fastcore/xml.py'),
|
|
838
851
|
'fastcore.xml._fix_k': ('xml.html#_fix_k', 'fastcore/xml.py'),
|
|
@@ -841,6 +854,11 @@ d = { 'settings': { 'branch': 'main',
|
|
|
841
854
|
'fastcore.xml._preproc': ('xml.html#_preproc', 'fastcore/xml.py'),
|
|
842
855
|
'fastcore.xml._to_attr': ('xml.html#_to_attr', 'fastcore/xml.py'),
|
|
843
856
|
'fastcore.xml._to_xml': ('xml.html#_to_xml', 'fastcore/xml.py'),
|
|
857
|
+
'fastcore.xml._xml_flatten': ('xml.html#_xml_flatten', 'fastcore/xml.py'),
|
|
858
|
+
'fastcore.xml._xml_keyword': ('xml.html#_xml_keyword', 'fastcore/xml.py'),
|
|
859
|
+
'fastcore.xml._xml_name': ('xml.html#_xml_name', 'fastcore/xml.py'),
|
|
860
|
+
'fastcore.xml._xml_qualify': ('xml.html#_xml_qualify', 'fastcore/xml.py'),
|
|
861
|
+
'fastcore.xml._xml_value': ('xml.html#_xml_value', 'fastcore/xml.py'),
|
|
844
862
|
'fastcore.xml.attrmap': ('xml.html#attrmap', 'fastcore/xml.py'),
|
|
845
863
|
'fastcore.xml.dict2xml': ('xml.html#dict2xml', 'fastcore/xml.py'),
|
|
846
864
|
'fastcore.xml.ft': ('xml.html#ft', 'fastcore/xml.py'),
|
|
@@ -69,6 +69,8 @@ Union types such as `int|str` try each type in turn, and `enum` types such as th
|
|
|
69
69
|
|
|
70
70
|
The decorated function is always the CLI entry point, and only the entry point gets `sys.argv`: argv is parsed when the function's file is run directly (`python foo.py`, `python -m foo`, or `%run foo.py`), or when it's called with no arguments from the top-level body of a directly-run file (which is how console script wrappers invoke it). Every other call is a plain Python call that ignores argv, whether from a notebook, the REPL, another function, or another `call_parse` function.
|
|
71
71
|
|
|
72
|
+
CLI calls return only `int` values (including `bool`) for console script exit codes; other return values are discarded. Plain Python calls preserve the return value. To report an error message, raise `CliError` rather than returning a string.
|
|
73
|
+
|
|
72
74
|
Use the `nested` keyword argument to create nested parsers, where earlier parsers consume only their known args from `sys.argv` before later parsers are used. This is useful to create one command line application that executes another. For example:
|
|
73
75
|
|
|
74
76
|
```sh
|
|
@@ -301,7 +303,8 @@ def _run_cli(func, nested, pos=None):
|
|
|
301
303
|
pargs,args = _pos_split(func, merge(args, args_from_prog(func, xtra)))
|
|
302
304
|
try:
|
|
303
305
|
res = tfunc(*pargs, **args)
|
|
304
|
-
|
|
306
|
+
if inspect.isawaitable(res): res = asyncio.run(res)
|
|
307
|
+
return res if isinstance(res, int) else None
|
|
305
308
|
except CliError as e: raise SystemExit(str(e))
|
|
306
309
|
|
|
307
310
|
def call_parse(func=None, nested=False, pos:list=None):
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Concise generation
|
|
1
|
+
"""Concise HTML generation and namespace-aware XML construction.
|
|
2
2
|
|
|
3
3
|
`ft(tag, *children, **attrs)` builds an `FT` tree — a lightweight XML/HTML element — and `to_xml` renders it (this is the foundation [fasthtml](https://fastht.ml) builds on). The common HTML tags are predefined as `ft` partials (`Div`, `P`, `A`, ...). Attributes are passed as keywords: use `klass` and `fr` for the reserved words `class` and `for`, `_` in an attr name becomes `-`, and attrs can be got and set on the object directly. Children can also be supplied after the attrs by calling the element, e.g. `Div(id='x')(child1, child2)`:
|
|
4
4
|
|
|
@@ -8,16 +8,18 @@ test_eq(to_xml(t), '<div hx-get="/get">\n <p class="a">hi</p>\n</div>\n')
|
|
|
8
8
|
test_eq(to_xml(Div(id='x')('child')), '<div id="x">child</div>\n')
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
+
`E(prefix='', attr_ns=None, ns=None)` creates a namespace-bound XML factory. `e = E('w', attr_ns='w', ns={'w': uri})` supports expressions such as `e.tcW(type='dxa', w=2400)`. Tags and attributes preserve case. `prefix__name` selects an attribute namespace; `attrs_` accepts literal names. Expressions compose with text and ordered collections, retain their namespace bindings, and serialize as UTF-8 with `.bytes()`. XML text is escaped and booleans become `true`/`false`. The existing `ft` and `to_xml` APIs keep their HTML behavior.
|
|
12
|
+
|
|
11
13
|
Docs: https://fastcore.fast.ai/xml.html.md"""
|
|
12
14
|
|
|
13
15
|
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/09_xml.ipynb.
|
|
14
16
|
|
|
15
17
|
# %% auto #0
|
|
16
18
|
__all__ = ['voids', 'attrmap', 'valmap', 'FT', 'ft', 'Html', 'Safe', 'to_xml', 'dict2xml', 'highlight', 'showtags', 'mk_getattr',
|
|
17
|
-
'Head', 'Title', 'Meta', 'Link', 'Style', 'Body', 'Pre', 'Code', 'Div', 'Span', 'P', 'H1', 'H2',
|
|
18
|
-
'H5', 'H6', 'Strong', 'Em', 'B', 'I', 'U', 'S', 'Strike', 'Sub', 'Sup', 'Hr', 'Br', 'Img', 'A',
|
|
19
|
-
'Ol', 'Li', 'Dl', 'Dt', 'Dd', 'Table', 'Thead', 'Tbody', 'Tfoot', 'Tr', 'Th', 'Td', 'Caption',
|
|
20
|
-
'Colgroup', 'Form', 'Input', 'Textarea', 'Button', 'Select', 'Option', 'Label', 'Fieldset', 'Legend',
|
|
19
|
+
'XML', 'E', 'Head', 'Title', 'Meta', 'Link', 'Style', 'Body', 'Pre', 'Code', 'Div', 'Span', 'P', 'H1', 'H2',
|
|
20
|
+
'H3', 'H4', 'H5', 'H6', 'Strong', 'Em', 'B', 'I', 'U', 'S', 'Strike', 'Sub', 'Sup', 'Hr', 'Br', 'Img', 'A',
|
|
21
|
+
'Nav', 'Ul', 'Ol', 'Li', 'Dl', 'Dt', 'Dd', 'Table', 'Thead', 'Tbody', 'Tfoot', 'Tr', 'Th', 'Td', 'Caption',
|
|
22
|
+
'Col', 'Colgroup', 'Form', 'Input', 'Textarea', 'Button', 'Select', 'Option', 'Label', 'Fieldset', 'Legend',
|
|
21
23
|
'Details', 'Summary', 'Main', 'Header', 'Footer', 'Section', 'Article', 'Aside', 'Figure', 'Figcaption',
|
|
22
24
|
'Mark', 'Small', 'Iframe', 'Object', 'Embed', 'Param', 'Video', 'Audio', 'Source', 'Canvas', 'Svg', 'Math',
|
|
23
25
|
'Script', 'Noscript', 'Template', 'Slot']
|
|
@@ -272,3 +274,142 @@ def mk_getattr(f):
|
|
|
272
274
|
return _getattr
|
|
273
275
|
|
|
274
276
|
__getattr__ = mk_getattr(ft)
|
|
277
|
+
|
|
278
|
+
# %% ../nbs/09_xml.ipynb #d6b837e2
|
|
279
|
+
from collections.abc import Iterator
|
|
280
|
+
from keyword import iskeyword
|
|
281
|
+
from xml.sax.saxutils import escape as xml_escape, quoteattr
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
# %% ../nbs/09_xml.ipynb #8cb06993
|
|
285
|
+
_xml_uri = 'http://www.w3.org/XML/1998/namespace'
|
|
286
|
+
_xmlns_uri = 'http://www.w3.org/2000/xmlns/'
|
|
287
|
+
_xml_start = (r'A-Z_a-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02ff\u0370-\u037d\u037f-\u1fff'
|
|
288
|
+
r'\u200c-\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd\U00010000-\U000effff')
|
|
289
|
+
_xml_local = re.compile(fr'[{_xml_start}][{_xml_start}\-.0-9\u00b7\u0300-\u036f\u203f-\u2040]*')
|
|
290
|
+
_xml_illegal = re.compile(r'[^\x09\x0a\x0d\x20-\ud7ff\ue000-\ufffd\U00010000-\U0010ffff]')
|
|
291
|
+
|
|
292
|
+
# %% ../nbs/09_xml.ipynb #b1031eff
|
|
293
|
+
def _xml_name(name):
|
|
294
|
+
parts = name.split(':')
|
|
295
|
+
if len(parts)>2 or any(not _xml_local.fullmatch(p) for p in parts): raise ValueError(f'Invalid XML name: {name!r}')
|
|
296
|
+
if parts[0]=='xmlns': raise ValueError('Use ns for namespace declarations')
|
|
297
|
+
return (parts[0], parts[1]) if len(parts)==2 else ('', name)
|
|
298
|
+
|
|
299
|
+
def _xml_value(value):
|
|
300
|
+
value = ('true' if value else 'false') if isinstance(value, bool) else str(value)
|
|
301
|
+
if _xml_illegal.search(value): raise ValueError('Illegal XML character')
|
|
302
|
+
return value
|
|
303
|
+
|
|
304
|
+
def _xml_flatten(children):
|
|
305
|
+
for child in children:
|
|
306
|
+
if isinstance(child, (list, tuple, L, Iterator)): yield from _xml_flatten(child)
|
|
307
|
+
elif child is not None: yield child
|
|
308
|
+
|
|
309
|
+
def _xml_qualify(name, prefix): return name if ':' in name or not prefix else f'{prefix}:{name}'
|
|
310
|
+
|
|
311
|
+
def _xml_keyword(name):
|
|
312
|
+
prefix, sep, local = name.partition('__')
|
|
313
|
+
if not sep: local = prefix
|
|
314
|
+
if local.endswith('_') and iskeyword(local[:-1]): local = local[:-1]
|
|
315
|
+
return f'{prefix}:{local}' if sep else local
|
|
316
|
+
|
|
317
|
+
# %% ../nbs/09_xml.ipynb #4abe3b40
|
|
318
|
+
class XML:
|
|
319
|
+
"A detached XML expression with fixed namespace bindings."
|
|
320
|
+
def __init__(self, tag, children, attrs, ns):
|
|
321
|
+
self.tag,self.attrs,self.ns = tag,attrs,ns
|
|
322
|
+
self.children = ()
|
|
323
|
+
self(*children)
|
|
324
|
+
|
|
325
|
+
def __call__(self, *children):
|
|
326
|
+
"Append children and return this expression."
|
|
327
|
+
self.children += tuple(self._child(c) for c in _xml_flatten(children))
|
|
328
|
+
return self
|
|
329
|
+
|
|
330
|
+
def _child(self, child):
|
|
331
|
+
if isinstance(child, XML): return child
|
|
332
|
+
if isinstance(child, str): return _xml_value(child)
|
|
333
|
+
raise TypeError('XML children require expressions, strings, or ordered collections of them')
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
# %% ../nbs/09_xml.ipynb #642fc6f0
|
|
337
|
+
@patch
|
|
338
|
+
def _render(self:XML, inherited, output):
|
|
339
|
+
output.append(f'<{self.tag}')
|
|
340
|
+
for prefix, uri in self.ns.items():
|
|
341
|
+
if inherited.get(prefix) != uri:
|
|
342
|
+
name = f'xmlns:{prefix}' if prefix else 'xmlns'
|
|
343
|
+
output.append(f' {name}={quoteattr(uri)}')
|
|
344
|
+
for name, value in self.attrs: output.append(f' {name}={quoteattr(value)}')
|
|
345
|
+
if not self.children:
|
|
346
|
+
output.append('/>')
|
|
347
|
+
return
|
|
348
|
+
output.append('>')
|
|
349
|
+
context = {**inherited, **self.ns}
|
|
350
|
+
for child in self.children:
|
|
351
|
+
if isinstance(child, XML): child._render(context, output)
|
|
352
|
+
else: output.append(xml_escape(child, {'\r': ' '}))
|
|
353
|
+
output.append(f'</{self.tag}>')
|
|
354
|
+
|
|
355
|
+
@patch
|
|
356
|
+
def __str__(self:XML):
|
|
357
|
+
output = []
|
|
358
|
+
self._render({'xml': _xml_uri}, output)
|
|
359
|
+
return ''.join(output)
|
|
360
|
+
|
|
361
|
+
@patch
|
|
362
|
+
def bytes(self:XML):
|
|
363
|
+
"Serialize as UTF-8, without formatting whitespace."
|
|
364
|
+
return str(self).encode('utf-8')
|
|
365
|
+
|
|
366
|
+
@patch
|
|
367
|
+
def _repr_markdown_(self:XML): return f'```xml\n{self}\n```'
|
|
368
|
+
|
|
369
|
+
# %% ../nbs/09_xml.ipynb #335a7366
|
|
370
|
+
class E:
|
|
371
|
+
"Create a namespace-bound XML factory."
|
|
372
|
+
_node_cls = XML
|
|
373
|
+
|
|
374
|
+
def __init__(
|
|
375
|
+
self, prefix='', # Default element prefix; empty uses the default namespace
|
|
376
|
+
*, attr_ns=None, # Default attribute prefix; None leaves attributes unqualified
|
|
377
|
+
ns=None, # Prefix-to-URI bindings, including prefixes used only in values
|
|
378
|
+
):
|
|
379
|
+
self._prefix,self._attr_ns = prefix,attr_ns
|
|
380
|
+
self._ns = {'': '', 'xml': _xml_uri, **(ns or {})}
|
|
381
|
+
for p in (prefix, attr_ns):
|
|
382
|
+
if p and (not _xml_local.fullmatch(p) or p=='xmlns'): raise ValueError(f'Invalid XML prefix: {p!r}')
|
|
383
|
+
for p, uri in self._ns.items():
|
|
384
|
+
if p and not _xml_local.fullmatch(p): raise ValueError(f'Invalid XML prefix: {p!r}')
|
|
385
|
+
if not isinstance(p, str) or not isinstance(uri, str): raise TypeError('Namespace prefixes and URIs require strings')
|
|
386
|
+
_xml_value(uri)
|
|
387
|
+
if p=='xmlns' or uri==_xmlns_uri or (p=='xml')!=(uri==_xml_uri) or p and not uri:
|
|
388
|
+
raise ValueError('Invalid reserved or empty namespace binding')
|
|
389
|
+
|
|
390
|
+
def _namespace(self, prefix):
|
|
391
|
+
if prefix not in self._ns: raise ValueError(f'Unknown XML prefix: {prefix!r}; supply ns')
|
|
392
|
+
return self._ns[prefix]
|
|
393
|
+
|
|
394
|
+
def __getattr__(self, name):
|
|
395
|
+
if name.startswith('_'): raise AttributeError(name)
|
|
396
|
+
if name.endswith('_') and iskeyword(name[:-1]): name = name[:-1]
|
|
397
|
+
return partial(self, name)
|
|
398
|
+
|
|
399
|
+
def __call__(self, name, /, *children, attrs_=None, **attrs):
|
|
400
|
+
tag = _xml_qualify(name, self._prefix)
|
|
401
|
+
pairs = [(_xml_qualify(_xml_keyword(k), self._attr_ns), v) for k,v in attrs.items()]
|
|
402
|
+
pairs += list((attrs_ or {}).items())
|
|
403
|
+
ns,seen,values = dict(self._ns),set(),[]
|
|
404
|
+
prefix, _ = _xml_name(tag)
|
|
405
|
+
if prefix: ns[prefix] = self._namespace(prefix)
|
|
406
|
+
for key, value in pairs:
|
|
407
|
+
if value is None: continue
|
|
408
|
+
prefix, local = _xml_name(key)
|
|
409
|
+
if prefix: ns[prefix] = self._namespace(prefix)
|
|
410
|
+
expanded = (ns[prefix] if prefix else '', local)
|
|
411
|
+
if expanded in seen: raise ValueError(f'Duplicate XML attribute: {key!r}')
|
|
412
|
+
seen.add(expanded)
|
|
413
|
+
values.append((key, _xml_value(value)))
|
|
414
|
+
return self._node_cls(tag, children, tuple(values), ns)
|
|
415
|
+
|
|
@@ -326,22 +326,17 @@ def rsync_multi(ip, files, user='ubuntu', persist='5m'):
|
|
|
326
326
|
for src,dst in files: shell(f'rsync -az -e "ssh -S {sock}" {src} {user}@{ip}:{dst}')
|
|
327
327
|
|
|
328
328
|
# %% ../nbs/03_xtras.ipynb #dda52646
|
|
329
|
-
def run(cmd, *rest, same_in_win=False, ignore_ex=False, as_bytes=False, stderr=True):
|
|
329
|
+
def run(cmd, *rest, same_in_win=False, ignore_ex=False, as_bytes=False, stderr=True, inp=None):
|
|
330
330
|
"Pass `cmd` (splitting with `shlex` if string) to `subprocess.run`; return `stdout`; raise `IOError` if fails"
|
|
331
|
-
# Even the command is same on Windows, we have to add `cmd /c `"
|
|
332
331
|
import subprocess
|
|
333
|
-
if rest:
|
|
334
|
-
if sys.platform == 'win32' and same_in_win:
|
|
335
|
-
cmd = ('cmd', '/c', cmd, *rest)
|
|
336
|
-
else:
|
|
337
|
-
cmd = (cmd,)+rest
|
|
332
|
+
if rest: cmd = ('cmd', '/c', cmd, *rest) if sys.platform == 'win32' and same_in_win else (cmd,)+rest
|
|
338
333
|
elif isinstance(cmd, str):
|
|
339
|
-
if sys.platform == 'win32' and same_in_win: cmd = 'cmd /c ' + cmd
|
|
340
334
|
import shlex
|
|
335
|
+
if sys.platform == 'win32' and same_in_win: cmd = 'cmd /c ' + cmd
|
|
341
336
|
cmd = shlex.split(cmd)
|
|
342
|
-
elif isinstance(cmd, list):
|
|
343
|
-
|
|
344
|
-
res = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
337
|
+
elif isinstance(cmd, list) and sys.platform == 'win32' and same_in_win: cmd = ['cmd', '/c'] + cmd
|
|
338
|
+
if isinstance(inp, str): inp = inp.encode()
|
|
339
|
+
res = subprocess.run(cmd, input=inp, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
345
340
|
stdout = res.stdout
|
|
346
341
|
if stderr and res.stderr: stdout += b' ;; ' + res.stderr
|
|
347
342
|
if not as_bytes: stdout = stdout.decode().strip()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastcore
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.25
|
|
4
4
|
Summary: Python supercharged for fastai development
|
|
5
5
|
Author-email: Jeremy Howard and Sylvain Gugger <infos@fast.ai>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -84,6 +84,7 @@ To install fastcore run: `conda install fastcore -c fastai` (if you use Anaconda
|
|
|
84
84
|
- `fastcore.test`: Simple testing functions
|
|
85
85
|
- `fastcore.foundation`: Mixins, delegation, composition, and more
|
|
86
86
|
- `fastcore.xtras`: Utility functions to help with functional-style programming, parallel processing, and more
|
|
87
|
+
- `fastcore.xml`: HTML with [`ft`](https://fastcore.fast.ai/xml.html#ft), and case-preserving, namespace-aware XML with [`E`](https://fastcore.fast.ai/xml.html#e) factories
|
|
87
88
|
|
|
88
89
|
To get started, we recommend you read through [the fastcore tour](https://fastcore.fast.ai/tour.html).
|
|
89
90
|
|
|
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
|
|
File without changes
|
|
File without changes
|