fastcore 2.2.26__tar.gz → 2.2.27__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.
Files changed (44) hide show
  1. {fastcore-2.2.26/fastcore.egg-info → fastcore-2.2.27}/PKG-INFO +1 -1
  2. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/__init__.py +2 -2
  3. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/aio.py +15 -3
  4. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/apisurface.py +10 -3
  5. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/docments.py +2 -2
  6. fastcore-2.2.27/fastcore/editskill.py +85 -0
  7. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/foundation.py +10 -4
  8. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/meta.py +11 -7
  9. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/nbio.py +2 -4
  10. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/parallel.py +3 -1
  11. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/script.py +30 -14
  12. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/tools.py +8 -4
  13. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/xml.py +14 -2
  14. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/xtras.py +26 -5
  15. {fastcore-2.2.26 → fastcore-2.2.27/fastcore.egg-info}/PKG-INFO +1 -1
  16. fastcore-2.2.26/fastcore/editskill.py +0 -67
  17. {fastcore-2.2.26 → fastcore-2.2.27}/CONTRIBUTING.md +0 -0
  18. {fastcore-2.2.26 → fastcore-2.2.27}/LICENSE +0 -0
  19. {fastcore-2.2.26 → fastcore-2.2.27}/README.md +0 -0
  20. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/_modidx.py +0 -0
  21. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/all.py +0 -0
  22. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/ansi.py +0 -0
  23. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/basics.py +0 -0
  24. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/dispatch.py +0 -0
  25. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/docscrape.py +0 -0
  26. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/funccall.py +0 -0
  27. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/imghdr.py +0 -0
  28. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/imports.py +0 -0
  29. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/nb_imports.py +0 -0
  30. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/net.py +0 -0
  31. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/py2pyi.py +0 -0
  32. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/shutil.py +0 -0
  33. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/style.py +0 -0
  34. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/test.py +0 -0
  35. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/transform.py +0 -0
  36. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/utils.py +0 -0
  37. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore/xdg.py +0 -0
  38. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore.egg-info/SOURCES.txt +0 -0
  39. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore.egg-info/dependency_links.txt +0 -0
  40. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore.egg-info/entry_points.txt +0 -0
  41. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore.egg-info/requires.txt +0 -0
  42. {fastcore-2.2.26 → fastcore-2.2.27}/fastcore.egg-info/top_level.txt +0 -0
  43. {fastcore-2.2.26 → fastcore-2.2.27}/pyproject.toml +0 -0
  44. {fastcore-2.2.26 → fastcore-2.2.27}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastcore
3
- Version: 2.2.26
3
+ Version: 2.2.27
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
@@ -38,7 +38,7 @@ test_eq(x.unique(), [1,2,3,4,5])
38
38
  Modules:
39
39
 
40
40
  - `fastcore.aio`: Bridging async and sync code: `run_sync`, `iter_sync`, `ctx_sync`, `athreaded`, `maybe_await`, and `then`, plus `Debounce` for coalescing bursts of calls
41
- - `fastcore.apisurface`: Turn operation metadata into documented, introspectable callables: real signatures, informative docstrings, and browsable grouped namespaces
41
+ - `fastcore.apisurface`: Signatures, documentation and grouped namespaces for generated API clients
42
42
  - `fastcore.basics`: Basic functionality used in the fastai library
43
43
  - `fastcore.docments`: Document parameters using comments.
44
44
  - `fastcore.editskill`: Text, file, cell, and notebook editing from `fastcore.tools` and `fastcore.nbio`, plus the conventions the whole fastai editing toolkit follows. Read this before working with the editing tools in any package that shares them.
@@ -55,4 +55,4 @@ Modules:
55
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.26"
58
+ __version__ = "2.2.27"
@@ -2,13 +2,25 @@
2
2
 
3
3
  ## Calling async code from sync code
4
4
 
5
- Async libraries return coroutines, which normally force every caller up the stack to become async too. `run_sync` (coroutines), `iter_sync` (async generators), and `ctx_sync` (async context managers) let ordinary sync code drive them instead, sharing a single event loop that runs on a background daemon thread, created on first use; `maybe_await(o)` awaits `o` only if it's awaitable, else returns it as-is.
5
+ Use these helpers to call async libraries without making your own code async:
6
+
7
+ - `run_sync` runs a coroutine and returns its result.
8
+ - `iter_sync` iterates an async generator.
9
+ - `ctx_sync` uses an async context manager in a `with` block.
10
+
11
+ They share an event loop on a background daemon thread, started on first use.
6
12
 
7
13
  ## Calling sync code from async code
8
14
 
9
- `athreaded` is the same bridge crossed in the other direction: it wraps a blocking function as an honest `async def`, running the original body in a worker thread so the event loop stays free. Use it to give async color to APIs that only exist in blocking form.
15
+ `athreaded` turns a blocking function into an async function that runs its body in a worker thread. This lets async code use blocking libraries without stalling the event loop.
16
+
17
+ `await maybe_await(o)` awaits `o` if it is awaitable and returns it unchanged otherwise.
18
+
19
+ `then(x, *fs)` applies each function to the preceding result. It returns a plain value when all steps are synchronous, or an awaitable if `x` or any step is awaitable.
20
+
21
+ This is useful for clients with both sync and async modes. A method can use `return then(self.gists.get(gid), ~Self.files.values(), first)` in either mode, without duplicating its body.
10
22
 
11
- `then` lets one function body serve sync and async callers alike. It applies each of `fs` in turn, awaiting anything awaitable along the way (the starting value or any step's result), and the caller gets back a plain value if the whole chain was sync, or an awaitable otherwise. This is what a convenience method on a client offering both sync and async modes needs: written as `return then(self.gists.get(gid), ~Self.files.values(), first)`, a sync client returns the file directly while an async client returns something to `await`, with no duplicated method. Because step results are awaited as part of the chain, steps may themselves be async calls; the flip side is that a step cannot return an awaitable *as* its value.
23
+ `then` awaits every awaitable returned by a step. Steps cannot pass awaitables through as data.
12
24
 
13
25
  Docs: https://fastcore.fast.ai/aio.html.md"""
14
26
 
@@ -1,8 +1,15 @@
1
- """Turn operation metadata into documented, introspectable callables: real signatures, informative docstrings, and browsable grouped namespaces
1
+ """Signatures, documentation and grouped namespaces for generated API clients
2
2
 
3
- A client generated from a machine-readable spec (an OpenAPI document, a Google Discovery document, an SDK symbol graph) is only pleasant to use if its runtime-created callables behave like hand-written ones: tab completion shows real parameters, `?` and `doc()` show real docs, and related operations sit together in namespaces you can browse. This module builds those pieces from plain *operation records*, ducks with these attributes: `name`, `group` (a nesting path: string or list), `summary`, `docs_url`, `params` (ordered parameter names), `required_params`, `param_types`, `param_defaults`, and `param_docs`. `mk_sig` turns a record into an `inspect.Signature` (spec names sanitized to Python identifiers via `sanitized_params`), `mk_doc` renders a docstring, and `OpGroup`/`mk_groups`/`full_docs` assemble named callables into an attribute-chained tree with markdown summaries at every level.
3
+ `apisurface` builds signatures, docstrings and grouped namespaces from API operation metadata. Generated clients can use it to support tab completion and documentation through `?` and `doc()`. `fastspec` uses it for HTTP clients generated from specifications.
4
4
 
5
- `fastspec` builds its HTTP clients on this layer.
5
+ An operation record can be any object with these attributes:
6
+
7
+ - `name`, `summary` and `docs_url` describe the operation.
8
+ - `group` gives its namespace as a string, or a list for nested groups.
9
+ - `params` lists parameter names in order. `required_params` identifies required parameters.
10
+ - `param_types`, `param_defaults` and `param_docs` map parameter names to their metadata.
11
+
12
+ `mk_sig` creates an `inspect.Signature` with Python parameter names. `mk_doc` creates a docstring. `OpGroup` and `mk_groups` organize operations into namespaces with attribute access. `full_docs` combines their overviews into Markdown.
6
13
 
7
14
  Docs: https://fastcore.fast.ai/apisurface.html.md"""
8
15
 
@@ -1,6 +1,6 @@
1
1
  """Document parameters using comments.
2
2
 
3
- A *docment* documents a parameter with a trailing comment on its line in the signature, right next to the name, type, and default it describes; `docments(f)` retrieves them programmatically, so tools (docs tables, CLIs like `fastcore.script`, ...) can use them. This replaces repeating parameter names in a specially-formatted docstring, which has to be kept in sync with the signature by hand:
3
+ A docment is a comment beside a parameter in a function signature. It keeps the parameter's description next to its name, type and default. `docments(f)` reads these comments for documentation tools and CLIs such as `fastcore.script`:
4
4
 
5
5
  ```python
6
6
  def add(
@@ -12,7 +12,7 @@ def add(
12
12
  test_eq(docments(add), {'a': 'The first operand', 'b': 'The second operand', 'return': 'The sum'})
13
13
  ```
14
14
 
15
- Comment lines *above* a param also work when one line isn't enough; `typing.Annotated` string metadata is an alternative to comments; numpy-style docstring sections are merged in when present; and `docments(f, full=True)` returns each param's default, type, and docment together.
15
+ For longer descriptions, put comment lines above the parameter. `docments` also reads `typing.Annotated` string metadata and NumPy-style docstrings. Pass `full=True` to retrieve each parameter's default, type and docment together.
16
16
 
17
17
  Docs: https://fastcore.fast.ai/docments.html.md"""
18
18
 
@@ -0,0 +1,85 @@
1
+ """Text, file, cell, and notebook editing from `fastcore.tools` and `fastcore.nbio`, plus the conventions the whole fastai editing toolkit follows. Read this before working with the editing tools in any package that shares them.
2
+
3
+ `from fastcore.editskill import *` loads the fastcore editing layer: the text primitives and file tools of `fastcore.tools`, and the notebook I/O and cell editors of `fastcore.nbio`. When installed, prefer `exhash` for hash-verified editing, `rgapi` for search, and `aidialog` or `dialoghelper` for dialogs.
4
+
5
+ ## Places
6
+
7
+ The tools edit strings in memory, files, notebook cells, and notebooks. File tools take a path. Cell tools take `path, cell_id` and edit that cell's source. `Notebook` and `NbCell` hold notebooks and cells in memory.
8
+
9
+ A Solveit dialog is an `.ipynb` whose cells represent notes, runnable code, and prompt/reply pairs. Cell tools work with notebook structure, regardless of which application produced the file. `aidialog.dlgskill` and `dialoghelper` provide tools for reading and editing dialog messages.
10
+
11
+ `open_doc` (in exhash) parses a file (`fname=`, or a `Path` as `src`), URL (an `https?://` str), or text (any other str) into a `Section` tree, with sections taken from Markdown headings, tree-sitter definitions in code, or md-heading cells in a notebook. A section points at a span of lines in a file, or a run of cells in a notebook. To change what a section contains, edit those lines or cells with the file and cell tools.
12
+
13
+ ## Naming
14
+
15
+ Function names follow these conventions:
16
+
17
+ - Operations on files, notebooks, cells, and messages use `verb_target`: `view_file`, `create_file`, `read_nb`, `write_nb`, `view_cell`, `validate_nb`, `view_msg`, and `view_dlg`. This includes `lnhashview_cell`. Names such as `find_msgs`, `add_msg`, `del_msgs`, and `find_cells` need no extra dialog or notebook prefix. `msg` identifies a dialog message and `cell` identifies a notebook cell. `summary_nb` returns rows for notebook cells.
18
+ - Text-editing primitives include `insert_line`, `del_lines`, `replace_lines`, and `str_replace`. File, cell, and message versions add a prefix, as in `file_del_lines`, `cell_del_lines`, and `msg_del_lines`. After their address arguments, these versions take the same arguments as the text primitive.
19
+
20
+ `str_replace` keeps the name and argument order established by Anthropic's text editor tool. `ast_replace` uses AST patterns to find edit targets. `exhash` takes commands containing hash-verified line addresses. These operations use the same file, cell, and message prefixes: `file_ast_replace`, `msg_ast_replace`, `file_exhash`, and `cell_exhash`.
21
+
22
+ Converters use `x2y` names, such as `nb2dict` and `cell2xml`. In aidialog, exactly one side is `dlg`. Converter methods use `to_y`, as in `nb.to_dict()`.
23
+
24
+ Plural names take multiple items: `view_cell` takes one cell, `lnhashview_cells` several, and `del_msgs` many.
25
+
26
+ ## Parameters
27
+
28
+ One vocabulary, identical wherever it appears:
29
+
30
+ - The place's address comes first (`text`; `path`; `path, cell_id`; a message `id`), the new text next, and ambient context last as keyword-only (message tools name their dialog that way).
31
+ - `start_line`/`end_line`: 1-based, inclusive, `None` for first/last, negative counting from the end. `del_lines` accepts no defaults: state the range.
32
+ - `re_filter`/`invert_filter`: restrict an edit to lines matching (or not matching) a regex, like ex's `g//` and `g!//`; combines with the range.
33
+ - Searches read patterns as regex by default. Editors read them as literal text unless `use_regex=True`.
34
+ - `nums` and `lnhashs` on any view: line numbers, or `lineno|hash|` addresses. `maxlen` caps characters per summary line; `trunc_out`/`trunc_in` truncate outputs and sources in dialog views.
35
+ - Search tools share one filter vocabulary: `pattern` first, `root='.'`, and the same include/exclude/ext/hidden/ignore block across `fd`, `ls`, `rg`, and `nbrg`. Variants differ by defaults, not API: `ls` is `fd` with listing defaults. Boolean filters narrow as `only_*` and widen as `include_*`.
36
+ - `context=` counts whatever units the place has: lines (or blocks in summary mode) for files, cells for notebooks, messages for dialogs. Dialog search defaults to context 1 because the neighbouring note usually explains the match.
37
+ - Every editor returns a diff ("none: No changes." when nothing changed). The diff is the verification: read it instead of re-viewing the target.
38
+
39
+ ## Functions and methods
40
+
41
+ Editing functions take a file path, save their changes, and return a diff. Editing methods change an object in memory. Save it explicitly to write the changes.
42
+
43
+ Methods omit the function's address arguments and the part of its name that identifies the object. For example, `cell_str_replace(path, cell_id, ...)` becomes `c.str_replace(...)` on an `NbCell`. `find_cells(path, pat)` becomes `nb.find_cells(pat)` on a `Notebook`.
44
+
45
+ Read functions return snapshot rows containing addresses, source, and metadata. Read methods return the objects themselves. Use one style at a time per file. Save before switching to file functions, then reopen the object before returning to methods.
46
+
47
+ ## Addresses
48
+
49
+ Edits accept line numbers, lnhash addresses, or section tokens. Get addresses while reading the target. Views accept `nums=True` or `lnhashs=True`. Searches can include addresses with `rg(lnhashs=True)`.
50
+
51
+ Prefer lnhash addresses when `exhash` is installed. The editor checks the hash against current content and rejects stale addresses. Plain line numbers are unverified and can shift after an edit. Re-view after each plain-line-number edit and apply multiple edits from bottom to top. Read `exhash.skill` for address formats and verified editing.
52
+
53
+ Section tokens identify sections in document outlines. In `1.6.|12|a3f2|,45|b1c3|`, `1.6.` is the section number. The rest is the lnhash range for its first and last lines. `d.at(token)` returns the section after checking its hash. `d.view(tok1, tok2)` prints the rendered text of both sections. Use the boundary range to edit the section: `file_exhash(path, ('12|a3f2|,45|b1c3|', 'c', new_text))`.
54
+
55
+ Read `exhash.skill` before working through large Markdown, code, or notebook files, or documentation from a URL. It describes `open_doc` tree searches and link following, including the llms.txt workflow.
56
+
57
+ When you don't know where to edit, start with a summary. `rgapi`'s `rg(summary=True)` and `nbrg`, aidialog's `summary_dlg`, and exhash's `open_doc` outlines show rows for blocks, cells, messages, or sections. Each row includes its address.
58
+
59
+ For prose, config, and other text organized into paragraphs, block summaries show the whole matched paragraph and its boundary addresses. Line-mode results show fragments that can require another view for context.
60
+
61
+ ## What's where
62
+
63
+ - `fastcore.tools`: text primitives, file tools, and `line_hash`/`lnhash`/`lnhash_at` for creating addresses without exhash installed.
64
+ - `fastcore.nbio`: notebook read/write/validate/repair, cell construction, cell editors, and the `Notebook`/`NbCell` session objects with their snapshot queries (`find_cells`, `summary_nb`).
65
+ - `exhash.skill`: hash-verified editing for files and cells, plus `open_doc` section outlines for Markdown, code, and notebooks; prefer it for edits where installed.
66
+ - `rgapi.skill`: `rg`/`fd`/`ls`/`nbrg` search with lnhash output, and `rgstr` to search text already in hand.
67
+ - `remold`: structural search and rewrite for Python source (declarative ast-grep rules, LibCST matcher transforms, symbol queries); the engine behind `ast_replace`.
68
+ - `aidialog.dlgskill`, `dialoghelper`: the dialog layer, including its own theory of dialogs and projections.
69
+
70
+ Docs: https://fastcore.fast.ai/tools.html.md and https://fastcore.fast.ai/nbio.html.md
71
+ """
72
+
73
+ from fastcore.tools import (insert_line, str_replace, strs_replace, replace_lines, del_lines, ast_replace,
74
+ file_insert_line, file_str_replace, file_strs_replace, file_replace_lines, file_del_lines, file_ast_replace,
75
+ view_file, create_file, line_hash, lnhash, lnhash_at)
76
+ from fastcore.nbio import (read_nb, write_nb, new_nb, mk_cell, validate_nb, validate_cell, repair_nb, repair_cell,
77
+ view_cell, cell_insert_line, cell_str_replace, cell_strs_replace, cell_replace_lines, cell_del_lines, cell_ast_replace, Notebook, NbCell, find_cells, summary_nb)
78
+
79
+ __all__ = ['insert_line', 'str_replace', 'strs_replace', 'replace_lines', 'del_lines', 'ast_replace',
80
+ 'file_insert_line', 'file_str_replace', 'file_strs_replace', 'file_replace_lines', 'file_del_lines', 'file_ast_replace',
81
+ 'view_file', 'create_file', 'line_hash', 'lnhash', 'lnhash_at',
82
+ 'read_nb', 'write_nb', 'new_nb', 'mk_cell', 'validate_nb', 'validate_cell', 'repair_nb', 'repair_cell',
83
+ 'view_cell', 'cell_insert_line', 'cell_str_replace', 'cell_strs_replace', 'cell_replace_lines', 'cell_del_lines', 'cell_ast_replace', 'Notebook', 'NbCell', 'find_cells', 'summary_nb']
84
+
85
+ __pyskill_params__ = {'replace_params': ('start_line', 'end_line', 'n_matches', 're_filter', 'invert_filter', 'use_regex')}
@@ -1,8 +1,10 @@
1
1
  """The `L` class and helpers for it
2
2
 
3
- `add_docs` (or the `docs` class decorator) attaches docstrings to a class and its methods from one dict kept separate from the code, so one-line methods stay one line; it also raises if any public method is left undocumented. `coll_repr` renders long list-likes as a length-prefixed preview like `(#2000) [0, 1, ...]`, and `flatmap(f, xs)` is a named `[y for x in xs for y in f(x)]`: a map where each input may produce zero, one, or many outputs.
3
+ `add_docs` attaches docstrings to a class and its methods from a dictionary. `docs` is its decorator form. Both check that every public method has documentation.
4
4
 
5
- `L` is a drop-in replacement for a python `list`. Inspired by [NumPy](http://www.numpy.org/), it supports advanced indexing — an int, slice, collection of ints, or boolean mask — and its methods (`map`, `filter`, `sorted`, `unique`, `itemgot`, `attrgot`, and many more) return a new `L`, encouraging simple expressive chains:
5
+ `coll_repr` shows a collection's length and a preview of its items. `flatmap(f, xs)` applies `f` to each item and concatenates the results.
6
+
7
+ `L` extends Python's list operations with indexing inspired by [NumPy](http://www.numpy.org/). You can index with an integer, slice, collection of integers or boolean mask. Methods such as `map`, `filter`, `sorted`, `unique`, `itemgot` and `attrgot` return an `L`:
6
8
 
7
9
  ```python
8
10
  t = L(1,2,3)
@@ -12,9 +14,13 @@ test_eq(t[[False,True,False,True]], [2,4])
12
14
  test_eq(t.map(lambda o:o*2), [2,4,6,8])
13
15
  ```
14
16
 
15
- Most `L` methods are also *curryable*: called on the class instead of an instance, they return a partial awaiting an iterable, so `L(lines).map(L.map(int))` converts each nested list. The curryable methods are `map`, `filter`, `groupby`, `argwhere`, `argfirst`, `first`, `last`, `sorted`, `reduce`, `partition`, `takewhile`, `dropwhile`, and `accumulate`. The `star` adapter wraps a function to unpack its *last* argument as individual args, so it works uniformly across these methods (`map` passes each item last; `reduce` passes `(acc, item)`, so only the item is unpacked); `rstar` unpacks in reversed order.
17
+ Call `L.map(int)` on the class to get a function that converts an iterable's items to integers. This curried form works with `map`, `filter`, `groupby`, `argwhere`, `argfirst`, `first`, `last`, `sorted`, `reduce`, `partition`, `takewhile`, `dropwhile` and `accumulate`.
18
+
19
+ `star(f)` unpacks the last argument before calling `f`. In `map`, that argument is the item. In `reduce`, it is the item after the accumulator. `rstar` reverses the unpacked arguments.
20
+
21
+ `L` has methods for `itertools` operations including `cycle`, `takewhile`, `dropwhile`, `accumulate`, `pairwise`, `batched`, `compress`, `permutations` and `combinations`.
16
22
 
17
- `L` also wraps the `itertools` verbs as methods: `cycle`, `takewhile`, `dropwhile`, `accumulate`, `pairwise`, `batched`, `compress`, `permutations`, `combinations`, plus `partition` (split into two `L`s by a predicate) and recursive `flatten` (strings kept atomic).
23
+ `partition` returns two collections according to a predicate. `flatten` recursively flattens nested iterables, leaving strings intact.
18
24
 
19
25
  Docs: https://fastcore.fast.ai/foundation.html.md"""
20
26
 
@@ -1,14 +1,18 @@
1
1
  """Metaclasses
2
2
 
3
- See this [blog post](https://realpython.com/python-metaclasses/) for more information about metaclasses.
3
+ These metaclasses customize object construction:
4
4
 
5
- - `FixSigMeta` preserves signature introspection (i.e. tab completion in IDEs) when inheritance through a `__new__` or a metaclass `__call__` would otherwise obscure it; the other metaclasses here all inherit from it.
6
- - `PrePostInitMeta` runs `__pre_init__` and `__post_init__` automatically around `__init__` (without having to call them yourself).
7
- - `AutoInit` is a `PrePostInitMeta` mixin that calls `super().__init__` for you.
8
- - `NewChkMeta` makes `C(x)` return `x` unchanged when `x` is already a `C` and no other args are passed (how `L` avoids re-wrapping an `L`).
9
- - `BypassNewMeta` casts an object of another class (`_bypass_type`) to this class without copying it.
5
+ - `FixSigMeta` preserves the constructor signature for introspection and tab completion. The other metaclasses inherit from it.
6
+ - `PrePostInitMeta` calls `__pre_init__` before `__init__` and `__post_init__` afterward.
7
+ - `AutoInit` is a `PrePostInitMeta` mixin that calls `super().__init__`.
8
+ - `NewChkMeta` makes `C(x)` return `x` when `x` is already a `C` and there are no other arguments.
9
+ - `BypassNewMeta` casts an object of `_bypass_type` to the new class without copying it.
10
10
 
11
- `use_kwargs`/`use_kwargs_dict` replace `**kwargs` in a signature with named params from an explicit list or dict, and `funcs_kwargs` lets a class accept method overrides as constructor kwargs. The one used everywhere in fastai code is `@delegates`: decorating `wrapper` with `@delegates(base)` replaces `**kwargs` in `wrapper`'s shown signature with `base`'s keyword parameters, so introspection and tab completion reveal the real options. Only params with defaults are copied over; `keep=True` retains `**kwargs`; `but=` excludes names; and on a class with no argument it delegates to the superclass:
11
+ See this [introduction to metaclasses](https://realpython.com/python-metaclasses/) for background.
12
+
13
+ `use_kwargs` and `use_kwargs_dict` replace `**kwargs` in a signature with parameters from a list or dictionary. `funcs_kwargs` lets a class accept method overrides as constructor arguments.
14
+
15
+ `@delegates(base)` adds `base`'s optional parameters to a wrapper's displayed signature for introspection and tab completion. Use `keep=True` to retain `**kwargs` and `but` to exclude parameters. On a class, `@delegates()` uses the superclass constructor:
12
16
 
13
17
  ```python
14
18
  def basefn(a, b=2, c=3): ...
@@ -761,11 +761,9 @@ MAXLEN = 180 # Most characters shown per displayed line
761
761
 
762
762
  # %% ../nbs/13_nbio.ipynb #80541be8
763
763
  def prev_line(txt, maxlen=MAXLEN, pre='', sep=''):
764
- "One-line preview `pre`+`sep`+`txt` capped at `maxlen`, blank-line runs shown as `¶`; a cut line carries `txt`'s size before `sep` and ends with the count of characters missing"
765
- n = len(txt)
764
+ "One-line preview capped at `maxlen`, with blank-line runs shown as `¶` and a trailing count of omitted characters"
766
765
  txt = re.sub(r'\n(?:\s*\n)*', '¶', txt)
767
- if len(pre)+len(sep)+len(txt)<=maxlen: return pre+sep+txt
768
- return truncstr(f'{pre}[{humanize(n)}]{sep}{txt}', maxlen, suf=lambda n: f'…[{humanize(n)}]')
766
+ return truncstr(f'{pre}{sep}{txt}', maxlen, suf=lambda n: f'…[{humanize(n)}]')
769
767
 
770
768
  # %% ../nbs/13_nbio.ipynb #804670bc
771
769
  class CellRow:
@@ -1,6 +1,8 @@
1
1
  """Threading and multiprocessing functions
2
2
 
3
- `parallel(f, items)` maps `f` over `items` using a process pool (`threadpool=True` for threads instead), with `n_workers`, optional `progress` bar, a `pause` between starts (to stagger e.g. web requests), and `return_exceptions` to collect errors instead of raising; `n_workers=0` runs serially, which makes debugging easy. `parallel_async` is the asyncio version, using a semaphore to limit concurrency. `@threaded` makes a function run in a `Thread` (or `Process`) whose eventual return value lands in its `result` attr, and `startthread`/`startproc` start one immediately.
3
+ `parallel(f, items)` applies `f` to each item using a process pool. Set `threadpool=True` to use threads. Set `n_workers` to control concurrency, or to 0 for serial execution when debugging. Optional arguments include a `progress` bar, a `pause` between starts, and `return_exceptions` to collect errors. `parallel_async` runs work concurrently with asyncio.
4
+
5
+ `@threaded` runs a function in a background thread and returns the thread. Read its `result` attribute after it finishes. Set `process=True` to run in a process. `startthread` and `startproc` start their decorated functions immediately.
4
6
 
5
7
  Docs: https://fastcore.fast.ai/parallel.html.md"""
6
8
 
@@ -15,7 +15,7 @@ def main(
15
15
  print(msg.upper() if upper else msg)
16
16
  ```
17
17
 
18
- Copy that into a file and run it, and you get a CLI with help, defaults, and error handling, with no `if __name__ == "__main__"` or argument parsing code:
18
+ `call_parse` provides argument parsing, help, defaults and error handling. Copy the example into a file and run it without adding an `if __name__ == "__main__"` block:
19
19
 
20
20
  ```
21
21
  $ examples/test_fastcore.py --help
@@ -31,11 +31,11 @@ options:
31
31
  --upper Convert to uppercase? (default: False)
32
32
  ```
33
33
 
34
- The function is still a plain Python function too, so it can also be called normally, e.g from a REPL such as Jupyter.
34
+ You can also call the function normally from Python, including in a Jupyter notebook.
35
35
 
36
36
  ## Annotated params
37
37
 
38
- For `argparse` features that docments can't express, use `typing.Annotated` type hints instead of plain types:
38
+ Use `typing.Annotated` for `argparse` options that docments can't express:
39
39
 
40
40
  ```python
41
41
  from fastcore.script import *
@@ -47,45 +47,61 @@ def main(msg:Annotated[str, "The message"],
47
47
  print(msg.upper() if upper else msg)
48
48
  ```
49
49
 
50
- The first element of `Annotated` is the parameter's type, and the first string in its metadata is its help. A `dict` in the metadata passes extra arguments to argparse: its keys can be `opt`, `action`, `nargs`, `const`, `choices`, `required`, and `version`. All but `opt` go straight to `add_argument`; `opt` is a bool that overrides whether the param is a flag or positional, which is normally inferred from whether it has a default.
50
+ The first element is the parameter's type. The first string in its metadata provides help text. Add a metadata dictionary to set `action`, `nargs`, `const`, `choices`, `required` or `version` arguments for `argparse.add_argument`.
51
+
52
+ The dictionary also accepts `opt`. Set it to `True` for a flag or `False` for a positional parameter. Without `opt`, parameters with defaults become flags.
51
53
 
52
54
  ## Short flags
53
55
 
54
- A capital letter in a parameter name declares a short flag: the capitalized letter becomes the short spelling and the lowercased name the long one, so `Resume:int=None` gets both `-r` and `--resume`. The capital can be any letter (`sUggest:str=None` gives `-u/--suggest`), only the first capital counts, and names without capitals get a long flag only. Underscores in optional parameter names appear as hyphens (`cache_dir` becomes `--cache-dir`), while the Python argument keeps its underscore. Since the flags are lowercased, the parameter's actual name keeps its capital -- so a Python caller writes `main(Resume=3)`, which usefully advertises that it's invoking a CLI entry point. Positional (default-less) parameters have no flags, so capitals there are left alone.
56
+ The first capital letter in an optional parameter's name declares a short flag:
57
+
58
+ - `Resume:int=None` gives `-r` and `--resume`.
59
+ - `sUggest:str=None` gives `-u` and `--suggest`.
60
+ - Names without capitals have only a long flag.
61
+
62
+ Long flags use lowercase and hyphens, such as `--cache-dir` for `cache_dir`. Python calls keep the parameter's spelling, such as `main(Resume=3)`. Positional parameters have no flags and keep their names unchanged.
55
63
 
56
64
  ## Positional params
57
65
 
58
- Parameters without a default are positional, and the rest are flags. A `*args` parameter is a variadic positional, taking zero or more values, and since Python makes any params after it keyword-only, they are flags. A `**kwargs` parameter is skipped: a CLI run passes nothing for it. Pass `pos` to `call_parse` (or to `anno_parser`) to keep named parameters positional even when they have a default, in which case they are optional on the command line and take the default when omitted. Command line order follows the signature, not the order of the names in `pos`. Naming a bool parameter in `pos` raises, since a flag takes no value.
66
+ Parameters without defaults are positional. Other parameters become flags. `*args` accepts zero or more positional values. Parameters after it are flags. CLI calls ignore `**kwargs`.
67
+
68
+ Pass parameter names in `pos` to `call_parse` or `anno_parser` to keep them positional even with defaults. Omitted values use those defaults. Command-line order follows the signature, regardless of the order in `pos`. A boolean flag cannot appear in `pos` because it takes no value.
59
69
 
60
70
  ## Param types
61
71
 
62
72
  A `bool` parameter is a `store_true` flag defaulting to `False`. If its default is `True` it becomes a `--no-` prefixed `store_false` flag instead, so passing the flag turns it off. Use `bool_arg` as the type when you want an explicit `--flag true|false` argument that honors its default.
63
73
 
64
- By default argparse repeats an option's name, upper-cased, as the placeholder for its value: `--path PATH`. That repeat says nothing useful, so help shows the annotation instead: `--path (str)`. `anno2str` gives the display name. The name describes the semantics rather than the mechanics: `Path` displays as `path`, and a union names each member once, dropping `str` when `path` is present since a path already is a string -- which is why `Path|str` is plain `path`. Enum params keep argparse's `{choice,...}` display, and positional params keep their name.
74
+ `argparse` normally repeats an option's name as its value placeholder, such as `--path PATH`. Here help shows the type instead, such as `--path (str)`.
75
+
76
+ `anno2str` formats the type name. It displays `Path` as `path`. Unions list each type once and omit `str` when `path` is present. For example, `Path|str` displays as `path`.
77
+
78
+ Enums show their choices as `{choice,...}`. Positional parameters show their names.
65
79
 
66
80
  Union types such as `int|str` try each type in turn, and `enum` types such as those from `str_enum` become argparse choices.
67
81
 
68
82
  ## The CLI entry point
69
83
 
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.
84
+ `call_parse` parses `sys.argv` when you run the function's file directly with `python foo.py`, `python -m foo` or `%run foo.py`. It also parses arguments on a zero-argument call from the top-level body of a directly run file. Console-script wrappers use this form.
85
+
86
+ Calls from a notebook, REPL or another function are ordinary Python calls. This includes calls from another `call_parse` function.
71
87
 
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.
88
+ CLI calls return integers, including booleans, as exit codes. They discard other return values. Python calls preserve return values. Raise `CliError` to report an error message to CLI users.
73
89
 
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:
90
+ Set `nested=True` when one CLI launches another. The outer parser removes the arguments it recognizes from `sys.argv`, leaving the rest for the inner CLI:
75
91
 
76
92
  ```sh
77
93
  myrunner --keyword 1 script.py -- <script.py args>
78
94
  ```
79
95
 
80
- A separating `--` after the first application's args is recommended though not always required, otherwise args may be parsed in unexpected ways. For example:
96
+ `--` is optional in some invocations. Use it to separate the applications' arguments and avoid cases such as:
81
97
 
82
98
  ```sh
83
99
  myrunner script.py -h
84
100
  ```
85
101
 
86
- would display `myrunner`'s help and not `script.py`'s.
102
+ `myrunner` handles `-h` here instead of passing it to `script.py`.
87
103
 
88
- A function usable both from the command line and from Python can call `is_cli` to tell which way it was invoked, e.g. returning a value to Python callers but printing it when run as a CLI:
104
+ Use `is_cli` to distinguish CLI execution from Python calls. Here the CLI prints a result that Python callers receive as a return value:
89
105
 
90
106
  ```python
91
107
  @call_parse
@@ -97,7 +113,7 @@ def sum_args(a:int=0, b:int=0):
97
113
  test_eq(sum_args(1,2), 3) # Python call: returns the value, prints nothing
98
114
  ```
99
115
 
100
- A command that cannot continue raises `CliError` with a message for the user. A CLI run prints just that message to stderr and exits with status 1. A Python call gets the exception to handle as it likes, so the raise site needs no `is_cli` branch:
116
+ Raise `CliError` when a command cannot continue. CLI execution prints its message to stderr and exits with status 1. Python callers can catch the exception:
101
117
 
102
118
  ```python
103
119
  @call_parse
@@ -1,10 +1,12 @@
1
1
  """Text and file editing primitives shared by the fastai editing tools
2
2
 
3
- The editors here are string-level: each takes `text` plus edit parameters and returns the new text, raising `ValueError` when an edit can't apply. The file tools below wrap them with path I/O and diff reporting; message-level wrappers live in aidialog. (This module previously held experimental LLM path-editing and command tools, superseded by safecmd, rgapi, and the tools here.) Naming, parameter, and workflow conventions for the whole editing toolkit, this module included, are documented in `fastcore.editskill`, which also re-exports these tools alongside `fastcore.nbio`'s.
3
+ The text editors take a string and return the edited text. Invalid edits raise `ValueError`. File editors read and write a path and return a diff. Aidialog provides corresponding message editors.
4
4
 
5
- `line_hash`, `lnhash`, and `lnhash_at` implement the [exhash](https://answerdotai.github.io/exhash) line-address format in pure Python: `lineno|hash|`, where the hash is 4 hex chars of crc32. They let any tool create lnhash-addressed views of text it holds, without depending on the exhash package.
5
+ Read `fastcore.editskill` for the editing toolkit's naming, parameter and workflow conventions. It exposes these tools alongside the notebook editors from `fastcore.nbio`.
6
6
 
7
- File tools wrap the primitives with path I/O, returning unified diffs of what changed ("none: No changes." / "error: ..." otherwise). The path is the first argument, e.g:
7
+ `line_hash`, `lnhash` and `lnhash_at` create [exhash](https://answerdotai.github.io/exhash) addresses without depending on the exhash package. Addresses use `lineno|hash|`. The hash is the low 16 bits of CRC32, formatted as four hexadecimal characters.
8
+
9
+ File editors take the path first and return a unified diff. An unchanged result returns `none: No changes.` Invalid edits return `error: ...`.
8
10
 
9
11
  view_file('~/a/b.py', 3)
10
12
  create_file('~/a/b/c.py', 'content here')
@@ -12,7 +14,9 @@ File tools wrap the primitives with path I/O, returning unified diffs of what ch
12
14
  file_del_lines('myfile.py', 2, 4)
13
15
  file_replace_lines('myfile.py', new_content=src) # no line numbers: replace the entire contents
14
16
 
15
- `file_str_replace`, `file_strs_replace`, and `file_del_lines` support `re_filter` and `invert_filter` for targeting only lines matching (or not matching) a regex, like ex's `g//` and `g!//`, combined with `start_line`/`end_line` to restrict to a region. `ast_replace(text, repls)` and `file_ast_replace(path, repls)` apply ast-grep `(pattern, replacement)` rules with `$VAR` metavariables (requires the optional `remold` package).
17
+ `file_str_replace`, `file_strs_replace` and `file_del_lines` support line ranges, `re_filter` and `invert_filter`. These work like ex's `g//` and `g!//` filters.
18
+
19
+ For Python syntax-tree replacements, use `ast_replace` or `file_ast_replace`. They accept ast-grep `(pattern, replacement)` rules with `$VAR` metavariables and require the optional `remold` package.
16
20
 
17
21
  Docs: https://fastcore.fast.ai/tools.html.md"""
18
22
 
@@ -1,6 +1,10 @@
1
1
  """Concise HTML generation and namespace-aware XML construction.
2
2
 
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)`:
3
+ `ft(tag, *children, **attrs)` builds an `FT` tree for HTML generation. `to_xml` renders the tree. [FastHTML](https://fastht.ml) uses these functions to generate HTML.
4
+
5
+ Common tags have constructors such as `Div`, `P` and `A`. Pass attributes as keywords, using `klass` for `class` and `fr` for `for`. Underscores in attribute names become hyphens. You can also get and set attributes on the element.
6
+
7
+ To supply children after attributes, call the element: `Div(id='x')(child1, child2)`.
4
8
 
5
9
  ```python
6
10
  t = Div(P('hi', klass='a'), hx_get='/get')
@@ -8,7 +12,15 @@ test_eq(to_xml(t), '<div hx-get="/get">\n <p class="a">hi</p>\n</div>\n')
8
12
  test_eq(to_xml(Div(id='x')('child')), '<div id="x">child</div>\n')
9
13
  ```
10
14
 
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`; subclasses override `attr_value` for vocabularies with other rules. The existing `ft` and `to_xml` APIs keep their HTML behavior.
15
+ `E` creates XML elements from Python calls. Its `ns` argument maps namespace prefixes to URIs. The `prefix` and `attr_ns` arguments set the default prefixes for element and attribute names.
16
+
17
+ For example, `e = E('w', attr_ns='w', ns={'w': uri})` uses `w` for both defaults. Calling `e.tcW(type='dxa', w=2400)` creates a `w:tcW` element with `w:type` and `w:w` attributes.
18
+
19
+ `E` preserves the case of tag and attribute names. Use `prefix__name` for an explicitly prefixed attribute, or `attrs_` for literal attribute names.
20
+
21
+ Nesting an element under a different parent does not change its namespace bindings.
22
+
23
+ XML serialization escapes text and writes booleans as `true` or `false`. Override `attr_value` for other conventions. `.bytes()` returns UTF-8. `ft` and `to_xml` retain their HTML behavior.
12
24
 
13
25
  Docs: https://fastcore.fast.ai/xml.html.md"""
14
26
 
@@ -1,10 +1,18 @@
1
1
  """Utility functions used in the fastai library
2
2
 
3
- Utilities (other than extensions to `Pathlib.Path`) for dealing with IO: `maybe_open` accepts a path or an already-open file, only closing what it opened; `run` passes a command line to `subprocess.run` and returns its `stdout`, raising `IOError` on failure; `atomic_save` writes via a temp file and renames, so readers never see a partial write; `untar_dir` extracts an archive the way you'd want (a lone top-level item lands directly in `dest`); and `globtastic` is a recursive glob with file/folder include and exclude filters.
3
+ IO utilities include:
4
4
 
5
- `Config` wraps a `ConfigParser` ini file with a single `DEFAULT` section: keys read as attributes, items, or `.get` with a default; `create=` writes initial contents if the file is missing; `types=` coerces values on read, resolving `Path` values relative to the config file's directory; and `Config.find(name)` searches a directory and its parents for the file.
5
+ - `maybe_open`: accept a path or an open file, closing only files it opens.
6
+ - `run`: run a command and return stdout; raise `IOError` on failure.
7
+ - `atomic_save`: write a temporary file, then rename it over the destination.
8
+ - `untar_dir`: extract an archive, creating a containing directory when needed.
9
+ - `globtastic`: recursively find files with include and exclude filters.
6
10
 
7
- `dict2obj` converts a (possibly nested) dict, or list of dicts, to attribute access: dicts become `AttrDict` and lists become `L`, so `d.b.c` replaces `d['b']['c']`; `obj2dict` reverses it:
11
+ `Config` reads and writes an ini file with one `DEFAULT` section. Access keys as attributes, items, or with `.get(key, default)`. Use `create=` to supply initial contents for a missing file.
12
+
13
+ `types=` converts values on read. `Path` values resolve relative to the config file's directory. `Config.find(name)` searches a directory and its parents for the file.
14
+
15
+ `dict2obj` converts nested dicts to `AttrDict` and lists to `L`, allowing attribute access such as `d.b.c`. `obj2dict` reverses the conversion:
8
16
 
9
17
  ```python
10
18
  d = dict2obj({'a':1, 'b':{'c':2, 'd':[3,4]}})
@@ -12,9 +20,22 @@ test_eq(d.b.c, 2)
12
20
  test_eq(d.b.d[1], 4)
13
21
  ```
14
22
 
15
- The following methods are added to the standard python library [Pathlib.Path](https://docs.python.org/3/library/pathlib.html#basic-use): `ls()` (dir contents as an `L`, with optional `file_type` MIME-prefix and `file_exts` filters); `read_json`/`write_json`, and `read_jsonl` which is safe for JSON Lines (only `\n` ends a record, unlike `splitlines`); `readlines`, `mk_write` (create parent dirs, then write), `delete`, `relpath`, and `normpath`. If `Path.BASE_PATH` is set, paths repr relative to it.
23
+ These methods extend [Pathlib.Path](https://docs.python.org/3/library/pathlib.html#basic-use):
24
+
25
+ - `ls()` lists directory contents as an `L`, optionally filtered by MIME prefix or extension.
26
+ - `read_json`, `write_json`, and `read_jsonl` handle JSON files.
27
+ - `readlines` reads lines; `mk_write` creates parent directories before writing.
28
+ - `delete`, `relpath`, and `normpath` provide file deletion and path conversions.
29
+
30
+ Set `Path.BASE_PATH` to display paths relative to that directory.
31
+
32
+ Other utilities include:
16
33
 
17
- Highlights among the rest: `exec_eval` runs a code string like a notebook cell, returning the last expression's value; `fenced` wraps text in a markdown code fence guaranteed longer than any run of the fence char inside it; `str_diff` returns a unified diff, `''` when the texts match; `unqid` and `friendly_name` generate random identifiers (a valid Python name, or a memorable `adjective-noun-...` string); and `flexicache` is an `lru_cache` with pluggable eviction policies such as `time_policy` and `mtime_policy`.
34
+ - `exec_eval`: run a code string and return its last expression, like a notebook cell.
35
+ - `fenced`: wrap text in a Markdown fence longer than any fence character run in the body.
36
+ - `str_diff`: return a unified diff, or `''` for identical text.
37
+ - `unqid` and `friendly_name`: generate random Python identifiers or memorable word-based names.
38
+ - `flexicache`: cache results with configurable expiration policies.
18
39
 
19
40
  Docs: https://fastcore.fast.ai/xtras.html.md"""
20
41
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastcore
3
- Version: 2.2.26
3
+ Version: 2.2.27
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
@@ -1,67 +0,0 @@
1
- """Text, file, cell, and notebook editing from `fastcore.tools` and `fastcore.nbio`, plus the conventions the whole fastai editing toolkit follows. Read this before working with the editing tools in any package that shares them.
2
-
3
- `from fastcore.editskill import *` loads the fastcore editing layer: the text primitives and file tools of `fastcore.tools`, and the notebook I/O and cell editors of `fastcore.nbio`. Sibling packages extend the same toolkit, and where they are installed prefer them as noted: `exhash` for hash-verified editing, `rgapi` for search, `aidialog`/`dialoghelper` for dialogs.
4
-
5
- ## Places
6
-
7
- Each editing function works on one place: text (a str in memory), a file (a path on disk), a cell (one cell's source in an .ipynb file, addressed by `path, cell_id`), or a notebook (the parsed .ipynb; `Notebook` and `NbCell` are its held-object forms). These are the representation layer: an .ipynb is a file of cells, whatever produced it. The dialog layer above adds the msg and dlg places: a Solveit dialog is an .ipynb whose cells are messages (notes, runnable code, prompt/reply pairs), and `aidialog.dlgskill` and `dialoghelper` provide the message tools, following the conventions here with their own nouns. The word picks the layer: cell tools answer representation questions ("why does Jupyter reject this file?"), msg tools answer content questions ("what does this message say?").
8
-
9
- The section layer sits above both. `open_doc` (in exhash) parses a file (`fname=`, or a `Path` as `src`), URL (an `https?://` str), or text (any other str) into a `Section` tree, with sections taken from Markdown headings, tree-sitter definitions in code, or md-heading cells in a notebook. A section points at a span of lines in a file, or a run of cells in a notebook. To change what a section contains, edit those lines or cells with the file and cell tools.
10
-
11
- ## Naming
12
-
13
- Two name shapes cover the toolkit, and the pivot is the verb's direct object:
14
-
15
- - An operation on a whole place takes the place as its noun: verb_place. `view_file`, `create_file`, `read_nb`, `write_nb`, `view_cell`, `validate_nb`; in the dialog layer `view_msg` and `view_dlg`. Coined verbs follow the same shape: `lnhashview_cell` is "lnhashview this cell". When the verb's object is instead the unit inside the place, and that unit names its place uniquely, no prefix is needed - the unit noun is the place signal: `find_msgs`, `add_msg`, `del_msgs` (msgs live only in dialogs), `find_cells`, `summary_nb`'s rows (cells live only in notebooks).
16
- - An operation within a place already owns its noun (`insert_line`, `del_lines`, `replace_lines`, `str_replace`), so the place prefixes as a namespace and the op name survives intact: place_op, as in `file_del_lines`, `cell_del_lines`, `msg_del_lines`. The bare op names are the text-level primitives, and every place version keeps the identical signature after its address arguments, so each family is learned once and recognized everywhere.
17
-
18
- The exceptions are deliberate and closed. `str_replace` keeps the name and argument order established by Anthropic's text editor tool. Instrument-named ops put the instrument first and elide their unit: `ast_replace` (the AST pattern is how the edit finds its target) and `exhash` (hash-verified line addresses travel inside its commands), place-prefixed like any other line-level op: `file_ast_replace`, `msg_ast_replace`, `file_exhash`, `cell_exhash`. Converters are named x2y (`nb2dict`, `cell2xml`; in aidialog, `dlg` on exactly one side of every converter), and on a held object the converter is a `to_y` method (`nb.to_dict()`). Plural marks arity: `view_cell` takes one cell, `lnhashview_cells` several, `del_msgs` many.
19
-
20
- ## Parameters
21
-
22
- One vocabulary, identical wherever it appears:
23
-
24
- - The place's address comes first (`text`; `path`; `path, cell_id`; a message `id`), the new text next, and ambient context last as keyword-only (message tools name their dialog that way).
25
- - `start_line`/`end_line`: 1-based, inclusive, `None` for first/last, negative counting from the end. `del_lines` accepts no defaults: state the range.
26
- - `re_filter`/`invert_filter`: restrict an edit to lines matching (or not matching) a regex, like ex's `g//` and `g!//`; combines with the range.
27
- - Searches read patterns as regex by default; editors read them as literal text until `use_regex=True`. Searching is read-only, so its default favors power; editing favors caution.
28
- - `nums` and `lnhashs` on any view: line numbers, or `lineno|hash|` addresses. `maxlen` caps characters per summary line; `trunc_out`/`trunc_in` truncate outputs and sources in dialog views.
29
- - Search tools share one filter vocabulary: `pattern` first, `root='.'`, and the same include/exclude/ext/hidden/ignore block across `fd`, `ls`, `rg`, and `nbrg`. Variants differ by defaults, not API: `ls` is `fd` with listing defaults. Boolean filters narrow as `only_*` and widen as `include_*`.
30
- - `context=` counts whatever units the place has: lines (or blocks in summary mode) for files, cells for notebooks, messages for dialogs. Dialog search defaults to context 1 because the neighbouring note usually explains the match: the why lives next to the what.
31
- - Every editor returns a diff ("none: No changes." when nothing changed). The diff is the verification: read it instead of re-viewing the target.
32
-
33
- ## Functions and methods
34
-
35
- Every operation has two shapes with one contract each. The function is a transaction: it addresses a file by path, applies the edit, writes, and returns a diff. The method is a session: it changes the object in hand, and nothing reaches disk until an explicit save. The correspondence is mechanical - the method is the function minus its address arguments, keeping its name except that a place word which became `self` drops: `cell_str_replace(path, cell_id, ...)` is `c.str_replace(...)` on a held `NbCell`, `find_cells(path, pat)` is `nb.find_cells(pat)` on a held `Notebook`. Function-side reads return plain snapshot rows carrying addresses, source, and meta; session-side reads return the objects themselves. Use one shape at a time per file: save before switching to functions, reopen after.
36
-
37
- ## Addresses
38
-
39
- Edits say where with line numbers, lnhash addresses, or section tokens. Take addresses from the read you were already doing instead of with a second look: views accept `nums=True` or `lnhashs=True`, and searches return addresses directly (`rg(lnhashs=True)`). Prefer lnhash addresses whenever `exhash` is installed: they are verified against current content at edit time, so a stale address fails loudly instead of editing nearby text, which is exactly why taking addresses early works. Plain line numbers are unverified and shift as edits apply, so re-view after each edit and apply multi-edits bottom-to-top. `exhash.skill` owns the address format and the verified editor. Section tokens make a long document navigable and editable a piece at a time. An outline row shows one, as in `1.6.|12|a3f2|,45|b1c3|`: the section number, then the lnhash addresses of its first and last lines. `d.at(token)` returns that section with its hash checked, `d.view(tok1, tok2)` prints the rendered text of each, and the same boundary pair drops straight into a range edit: `file_exhash(path, ('12|a3f2|,45|b1c3|', 'c', new_text))`. Read `exhash.skill` before working through a large Markdown, code, or notebook file, or before reading documentation from a URL: `open_doc` also searches within a tree and follows links, which is how the llms.txt docs workflow runs.
40
-
41
- When you don't yet know where to edit, locate with a summary first: `rgapi`'s `rg(summary=True)` and `nbrg`, aidialog's `summary_dlg`, and exhash's `open_doc` outlines each show one row per natural unit (block, cell, message, section), carrying the unit's address. For prose, config, and other paragraph-shaped text, blocks are usually the right unit for reading too: one summary row shows the whole matched paragraph with its boundary addresses, where a line-mode hit shows a fragment that then needs a context view. Summaries locate, views read, addresses edit, diffs confirm.
42
-
43
- ## What's where
44
-
45
- - `fastcore.tools`: text primitives, file tools, and `line_hash`/`lnhash`/`lnhash_at` for creating addresses without exhash installed.
46
- - `fastcore.nbio`: notebook read/write/validate/repair, cell construction, cell editors, and the `Notebook`/`NbCell` session objects with their snapshot queries (`find_cells`, `summary_nb`).
47
- - `exhash.skill`: hash-verified editing for files and cells, plus `open_doc` section outlines for Markdown, code, and notebooks; prefer it for edits where installed.
48
- - `rgapi.skill`: `rg`/`fd`/`ls`/`nbrg` search with lnhash output, and `rgstr` to search text already in hand.
49
- - `remold`: structural search and rewrite for Python source (declarative ast-grep rules, LibCST matcher transforms, symbol queries); the engine behind `ast_replace`.
50
- - `aidialog.dlgskill`, `dialoghelper`: the dialog layer, including its own theory of dialogs and projections.
51
-
52
- Docs: https://fastcore.fast.ai/tools.html.md and https://fastcore.fast.ai/nbio.html.md
53
- """
54
-
55
- from fastcore.tools import (insert_line, str_replace, strs_replace, replace_lines, del_lines, ast_replace,
56
- file_insert_line, file_str_replace, file_strs_replace, file_replace_lines, file_del_lines, file_ast_replace,
57
- view_file, create_file, line_hash, lnhash, lnhash_at)
58
- from fastcore.nbio import (read_nb, write_nb, new_nb, mk_cell, validate_nb, validate_cell, repair_nb, repair_cell,
59
- view_cell, cell_insert_line, cell_str_replace, cell_strs_replace, cell_replace_lines, cell_del_lines, cell_ast_replace, Notebook, NbCell, find_cells, summary_nb)
60
-
61
- __all__ = ['insert_line', 'str_replace', 'strs_replace', 'replace_lines', 'del_lines', 'ast_replace',
62
- 'file_insert_line', 'file_str_replace', 'file_strs_replace', 'file_replace_lines', 'file_del_lines', 'file_ast_replace',
63
- 'view_file', 'create_file', 'line_hash', 'lnhash', 'lnhash_at',
64
- 'read_nb', 'write_nb', 'new_nb', 'mk_cell', 'validate_nb', 'validate_cell', 'repair_nb', 'repair_cell',
65
- 'view_cell', 'cell_insert_line', 'cell_str_replace', 'cell_strs_replace', 'cell_replace_lines', 'cell_del_lines', 'cell_ast_replace', 'Notebook', 'NbCell', 'find_cells', 'summary_nb']
66
-
67
- __pyskill_params__ = {'replace_params': ('start_line', 'end_line', 'n_matches', 're_filter', 'invert_filter', 'use_regex')}
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