nbdev 3.3.4__tar.gz → 3.3.6__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 (40) hide show
  1. {nbdev-3.3.4/nbdev.egg-info → nbdev-3.3.6}/PKG-INFO +2 -2
  2. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev/__init__.py +2 -1
  3. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev/_modidx.py +3 -4
  4. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev/frontmatter.py +7 -30
  5. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev/migrate.py +2 -2
  6. nbdev-3.3.6/nbdev/moddocs.py +84 -0
  7. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev/processors.py +0 -1
  8. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev/release.py +6 -3
  9. {nbdev-3.3.4 → nbdev-3.3.6/nbdev.egg-info}/PKG-INFO +2 -2
  10. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev.egg-info/SOURCES.txt +1 -0
  11. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev.egg-info/requires.txt +1 -1
  12. {nbdev-3.3.4 → nbdev-3.3.6}/pyproject.toml +1 -1
  13. {nbdev-3.3.4 → nbdev-3.3.6}/CONTRIBUTING.md +0 -0
  14. {nbdev-3.3.4 → nbdev-3.3.6}/LICENSE +0 -0
  15. {nbdev-3.3.4 → nbdev-3.3.6}/MANIFEST.in +0 -0
  16. {nbdev-3.3.4 → nbdev-3.3.6}/README.md +0 -0
  17. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev/clean.py +0 -0
  18. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev/cli.py +0 -0
  19. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev/config.py +0 -0
  20. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev/diff.py +0 -0
  21. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev/doclinks.py +0 -0
  22. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev/export.py +0 -0
  23. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev/extract_attachments.py +0 -0
  24. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev/imports.py +0 -0
  25. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev/maker.py +0 -0
  26. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev/merge.py +0 -0
  27. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev/process.py +0 -0
  28. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev/qmd.py +0 -0
  29. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev/quarto.py +0 -0
  30. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev/scrubmagics.py +0 -0
  31. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev/serve.py +0 -0
  32. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev/serve_drv.py +0 -0
  33. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev/showdoc.py +0 -0
  34. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev/skill.py +0 -0
  35. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev/sync.py +0 -0
  36. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev/test.py +0 -0
  37. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev.egg-info/dependency_links.txt +0 -0
  38. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev.egg-info/entry_points.txt +0 -0
  39. {nbdev-3.3.4 → nbdev-3.3.6}/nbdev.egg-info/top_level.txt +0 -0
  40. {nbdev-3.3.4 → nbdev-3.3.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nbdev
3
- Version: 3.3.4
3
+ Version: 3.3.6
4
4
  Summary: Create delightful software with Jupyter Notebooks
5
5
  Author-email: "Jeremy Howard and the fast.ai community" <j@fast.ai>
6
6
  License: Apache-2.0
@@ -16,7 +16,7 @@ Classifier: License :: OSI Approved :: Apache Software License
16
16
  Requires-Python: >=3.10
17
17
  Description-Content-Type: text/markdown
18
18
  License-File: LICENSE
19
- Requires-Dist: fastcore>=2.1.11
19
+ Requires-Dist: fastcore>=2.2.3
20
20
  Requires-Dist: execnb>=0.2.8
21
21
  Requires-Dist: astunparse
22
22
  Requires-Dist: ghapi>=2.0.2
@@ -3,9 +3,10 @@
3
3
  Modules:
4
4
 
5
5
  - `nbdev.extract_attachments`: A preprocessor that extracts all of the attachments from the notebook file. The extracted attachments are returned in the 'resources' dictionary.
6
+ - `nbdev.moddocs`: # Module docs: creating them from existing notebooks
6
7
  - `nbdev.skill`: Author clear, executable nbdev notebooks where code, prose, examples, outputs, and tests form one coherent narrative."""
7
8
 
8
- __version__ = "3.3.4"
9
+ __version__ = "3.3.6"
9
10
 
10
11
  from .doclinks import nbdev_export
11
12
  from .showdoc import show_doc
@@ -141,10 +141,8 @@ d = { 'settings': { 'branch': 'main',
141
141
  'nbdev.frontmatter.FrontmatterProc.end': ( 'api/frontmatter.html#frontmatterproc.end',
142
142
  'nbdev/frontmatter.py'),
143
143
  'nbdev.frontmatter._dict2fm': ('api/frontmatter.html#_dict2fm', 'nbdev/frontmatter.py'),
144
- 'nbdev.frontmatter._fm2dict': ('api/frontmatter.html#_fm2dict', 'nbdev/frontmatter.py'),
145
- 'nbdev.frontmatter._insertfm': ('api/frontmatter.html#_insertfm', 'nbdev/frontmatter.py'),
146
- 'nbdev.frontmatter._md2dict': ('api/frontmatter.html#_md2dict', 'nbdev/frontmatter.py'),
147
- 'nbdev.frontmatter.nb_frontmatter': ('api/frontmatter.html#nb_frontmatter', 'nbdev/frontmatter.py')},
144
+ 'nbdev.frontmatter._fm2dict_md': ('api/frontmatter.html#_fm2dict_md', 'nbdev/frontmatter.py'),
145
+ 'nbdev.frontmatter._insertfm': ('api/frontmatter.html#_insertfm', 'nbdev/frontmatter.py')},
148
146
  'nbdev.imports': {},
149
147
  'nbdev.maker': { 'nbdev.maker.ModuleMaker': ('api/maker.html#modulemaker', 'nbdev/maker.py'),
150
148
  'nbdev.maker.ModuleMaker.__init__': ('api/maker.html#modulemaker.__init__', 'nbdev/maker.py'),
@@ -210,6 +208,7 @@ d = { 'settings': { 'branch': 'main',
210
208
  'nbdev.migrate.migrate_nb': ('api/migrate.html#migrate_nb', 'nbdev/migrate.py'),
211
209
  'nbdev.migrate.nbdev_migrate': ('api/migrate.html#nbdev_migrate', 'nbdev/migrate.py'),
212
210
  'nbdev.migrate.nbdev_migrate_config': ('api/migrate.html#nbdev_migrate_config', 'nbdev/migrate.py')},
211
+ 'nbdev.moddocs': {},
213
212
  'nbdev.process': { 'nbdev.process.NBProcessor': ('api/process.html#nbprocessor', 'nbdev/process.py'),
214
213
  'nbdev.process.NBProcessor.__init__': ('api/process.html#nbprocessor.__init__', 'nbdev/process.py'),
215
214
  'nbdev.process.NBProcessor._proc': ('api/process.html#nbprocessor._proc', 'nbdev/process.py'),
@@ -5,7 +5,7 @@ Docs: https://nbdev.fast.ai/api/frontmatter.html.md"""
5
5
  # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/api/09_frontmatter.ipynb.
6
6
 
7
7
  # %% auto #0
8
- __all__ = ['nb_frontmatter', 'FrontmatterProc']
8
+ __all__ = ['FrontmatterProc']
9
9
 
10
10
  # %% ../nbs/api/09_frontmatter.ipynb #2398f5ef-06d3-4890-8a54-7cf4f81f3894
11
11
  from .imports import *
@@ -21,38 +21,15 @@ _RE_FM_BASE=r'''^---\s*
21
21
  (.*?\S+.*?)
22
22
  ---\s*'''
23
23
 
24
- _re_fm_nb = re.compile(_RE_FM_BASE+'$', flags=re.DOTALL)
25
24
  _re_fm_md = re.compile(_RE_FM_BASE, flags=re.DOTALL)
26
25
 
26
+
27
27
  # %% ../nbs/api/09_frontmatter.ipynb #1725f3b9
28
- def _fm2dict(s:str, nb=True):
29
- "Load YAML frontmatter into a `dict`"
30
- re_fm = _re_fm_nb if nb else _re_fm_md
31
- match = re_fm.search(s.strip())
28
+ def _fm2dict_md(s:str):
29
+ "Load YAML frontmatter opening a markdown file (body allowed) into a `dict`"
30
+ match = _re_fm_md.search(s.strip())
32
31
  return yaml.safe_load(match.group(1)) if match else {}
33
32
 
34
- def _md2dict(s:str):
35
- "Convert H1 formatted markdown cell to frontmatter dict"
36
- if '#' not in s: return {}
37
- m = re.search(r'^#\s+(\S.*?)\s*$', s, flags=re.MULTILINE)
38
- if not m: return {}
39
- res = {'title': m.group(1)}
40
- m = re.search(r'^>\s+(\S.*?)\s*$', s, flags=re.MULTILINE)
41
- if m: res['description'] = m.group(1)
42
- r = re.findall(r'^-\s+(\S.*:.*\S)\s*$', s, flags=re.MULTILINE)
43
- if r:
44
- try: res.update(yaml.safe_load('\n'.join(r)))
45
- except Exception as e: warn(f'Failed to create YAML dict for:\n{r}\n\n{e}\n')
46
- return res
47
-
48
- # %% ../nbs/api/09_frontmatter.ipynb #4ba11b21
49
- def nb_frontmatter(nb):
50
- "Get frontmatter dict from `nb` without modifying cells"
51
- raw = first(c for c in nb.cells if c.cell_type=='raw')
52
- md = first(c for c in nb.cells if c.cell_type=='markdown')
53
- res = _md2dict(md.source) if md else {}
54
- if raw: res.update(_fm2dict(raw.source))
55
- return res
56
33
 
57
34
  # %% ../nbs/api/09_frontmatter.ipynb #1b5d9d32
58
35
  def _dict2fm(d): return f'---\n{yaml.dump(d)}\n---\n\n'
@@ -71,8 +48,8 @@ class FrontmatterProc(Processor):
71
48
  cell.source = None
72
49
 
73
50
  def cell(self, cell):
74
- if cell.cell_type=='raw': self._update(_fm2dict, cell)
75
- elif cell.cell_type=='markdown' and 'title' not in self.fm: self._update(_md2dict, cell)
51
+ if cell.cell_type=='raw': self._update(cell_frontmatter, cell)
52
+ elif cell.cell_type=='markdown' and 'title' not in self.fm: self._update(md_frontmatter, cell)
76
53
 
77
54
  def end(self):
78
55
  self.nb.frontmatter_ = self.fm
@@ -11,7 +11,7 @@ __all__ = ['MigrateProc', 'fp_md_fm', 'migrate_nb', 'migrate_md', 'nbdev_migrate
11
11
  from .process import *
12
12
  from fastcore.nbio import first_code_ln, langs
13
13
  from .frontmatter import *
14
- from .frontmatter import _fm2dict, _re_fm_md, _dict2fm, _insertfm
14
+ from .frontmatter import _fm2dict_md, _re_fm_md, _dict2fm, _insertfm
15
15
  from .processors import *
16
16
  from .config import get_config, read_nb, set_version, pyproject_tmpl, nbdev_defaults
17
17
  from .sync import write_nb
@@ -98,7 +98,7 @@ def fp_md_fm(path):
98
98
  "Make fastpages front matter in markdown files quarto compliant."
99
99
  p = Path(path)
100
100
  md = p.read_text()
101
- fm = _fm2dict(md, nb=False)
101
+ fm = _fm2dict_md(md)
102
102
  if fm:
103
103
  fm = _fp_convert(fm, path)
104
104
  return _re_fm_md.sub(_dict2fm(fm), md)
@@ -0,0 +1,84 @@
1
+ r"""# Module docs: creating them from existing notebooks
2
+
3
+ Module docs are the LLM-facing documentation channel of an nbdev project: module docstrings, the package docstring, and `llms.txt`, all generated by `nbdev-export`. They ship inside the code, so they are there for every user of the library with no separate network lookup, and they cannot be stale relative to the installed version. They also make learning uniform. One call, `doc(foo)`, teaches a package, a module, a class, or a function, and plain `help(foo)` shows the same text. A reader works progressively: `llms.txt` or the package docstring says which modules matter, `doc(module)` teaches one module in a single read, and the `Docs:` URL ending each docstring leads to the full page when needed.
4
+
5
+ This guide covers one task. A project's notebooks already exist, and you are creating the module docs from them. General notebook authoring, and the `#| export`/`#| exportd` docstring mechanics, are `doc(nbdev.skill)`'s job. Read it first.
6
+
7
+ ## Creating a module's docs from its notebook
8
+
9
+ The notebook already contains the documentation. Its author made the content decisions when writing it: which ideas get prose, which examples demonstrate them, what matters. Creating module docs is a projection of that material, not new writing. The work is deciding which prose becomes the docstring, and reshaping it to stand alone.
10
+
11
+ Start with the baseline. Run `doc(module)` as-is and note what a reader gets today, usually the bare summary line. Then read the whole notebook, sorting its markdown into two kinds:
12
+
13
+ - Standalone prose, which teaches a concept without depending on the cells around it. These are tagging candidates.
14
+ - Cell-adjacent prose ("...to this:", "The code for `Int` is shown below:", six cells walking one function's variations). These cannot export as-is.
15
+
16
+ The mix decides between two options, and the user picks:
17
+
18
+ **Option 1: extract.** Build the docstring from the notebook's own narrative. When a cell stands alone, tag it `#| export` where it sits. When it nearly stands alone, reshape lightly first:
19
+
20
+ - Split the cell so only the standalone part is tagged.
21
+ - End a summary with a colon so it reads straight into a `#| exportd` demo.
22
+ - Fix wording that only works on the page, such as "the helpers below" or "as shown above".
23
+
24
+ Where a section's prose is all cell-adjacent, write one new summary cell under its heading, condensing what those cells teach: the idioms a reader could not guess from signatures, with the long tail left to the docs page. This improves the docs page at the same time, since a section that jumped straight into per-function detail was missing its overview anyway. When most of a module's docs can be tagged nearly as-is, the original notebook was authored well, and the docstring comes almost for free.
25
+
26
+ **Option 2: front block.** Write the docstring as a few fresh markdown cells right after the title, optionally with `#| exportd` demos between them, all tagged, forming one self-contained overview read top to bottom. Reach for this when extraction keeps producing fragments, when the notebook's structure doesn't match the story the docstring should tell, or when the user simply prefers it. It is the simplest safe default. Nothing the author wrote is touched, so nothing on the page changes, except that the page gains an overview at the top, which usually helps. Don't push for restructuring the whole notebook when a front block serves.
27
+
28
+ **Demos.** An existing example cell can often be tagged `#| exportd` as-is. A new demo must run after the definitions it uses, so its notebook position is constrained, but its docstring position is not. Only tagged cells assemble, so a summary and its demo sit adjacent in the docstring however many definition cells separate them in the notebook. Run every demo in notebook order and see it pass. Run code to check every prose claim too, since old prose can be stale, and a docstring stating something false is worse than one stating nothing.
29
+
30
+ **Iterate and review.** Preview with `nbdev.export.nb_mdoc(nbname)`, which shows the docstring the notebook would produce, until it reads well top to bottom. Then show the user every new and changed cell verbatim, as markdown and code with their directives. Cell ids and diffs are not reviewable. The actual text is. After export, read `doc(module)` the way the eventual reader will.
31
+
32
+ ## Creating the package docs from index.ipynb
33
+
34
+ The same projection applies at package level. `index.ipynb` already carries the project intro, and tagging markdown there feeds both the package docstring (written into `__init__.py`) and `llms.txt`. The pieces:
35
+
36
+ - The summary line is `[project].description` from `pyproject.toml`.
37
+ - Tag the intro paragraphs `#| export`. Tips lists, curated links, and a short `#| exportd` quick-start demo all project well. Installation instructions and marketing positioning stay untagged.
38
+ - The `Modules:` list assembles itself: every module whose docstring now says more than the default summary-plus-link is listed with its summary line. Finishing a module's docs is what lists it, so do the modules first and the package list follows.
39
+ - `llms.txt` is the same parts in llms.txt shape, written into `nbs/` on export.
40
+
41
+ ## Ask the user
42
+
43
+ - Which modules get docs at all, before starting. Internal, vendored, and niche modules can stay bare, which also keeps them out of the package listing. Leaving a module bare is itself a curation decision.
44
+ - The cut for each module, before writing: propose a summary paragraph and demo for the defining idioms, a sentence naming the supporting functions, and nothing for the rest, then wait for a steer.
45
+ - Whether existing page prose may be rewritten in place, since that changes the docs site too.
46
+ - Extract or front block. Present the choice with your read of how well the existing prose extracts, and let the user pick.
47
+ - Exact-output assertions in demos, when an exact string arguably is the contract, such as a rendered template or a signature.
48
+ - Anything discovered along the way. Report and propose stale claims in old prose, candidate deprecations, and missing features, and let the user decide. API changes are never part of a docs pass.
49
+
50
+ ## Worked example: fastcore.script
51
+
52
+ `fastcore/nbs/06_script.ipynb` opens with a bare title cell, then a tagged overview whose first line becomes the module summary:
53
+
54
+ # Script - CLI
55
+
56
+ [cell] #| export
57
+ Creates a CLI from a Python function decorated with `call_parse`.
58
+
59
+ The function's parameters become the script's arguments, its docstring becomes the program description, and its [docments](https://fastcore.fast.ai/docments.html) comments become the help for each argument.
60
+
61
+ Deeper in the notebook, after `is_cli` is defined, an existing summary and demo pair was tagged where it stood:
62
+
63
+ [cell] #| export
64
+ 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 (or exiting with an error code) when run as a CLI:
65
+
66
+ [cell] #| exportd
67
+ @call_parse
68
+ def sum_args(a:int=0, b:int=0):
69
+ "Add `a` and `b`"
70
+ if is_cli(): print(a+b)
71
+ else: return a+b
72
+
73
+ test_eq(sum_args(1,2), 3) # Python call: returns the value, prints nothing
74
+
75
+ In the assembled docstring the pair renders as the summary followed by a fenced python block, and the package artifacts pick the module up automatically. Its line in fastcore's `llms.txt`:
76
+
77
+ - [fastcore.script](https://fastcore.fast.ai/script.html.md): Creates a CLI from a Python function decorated with `call_parse`.
78
+
79
+ Points to notice:
80
+
81
+ - The docstring is a small fraction of the docs page, yet answers most usage questions. That ratio is the target.
82
+ - The overview and the `is_cli` pair were existing cells, tagged in place with light tightening.
83
+ - The "Param types" summary in the same notebook was condensed from scattered examples into a new cell, improving the page and the docstring together.
84
+ - The demo asserts the behavior it teaches, and its assertion runs in the notebook's test suite from then on."""
@@ -18,7 +18,6 @@ from .process import *
18
18
  from .showdoc import *
19
19
  from .doclinks import *
20
20
  from .frontmatter import *
21
- from .frontmatter import _fm2dict
22
21
 
23
22
  from fastcore.nbio import *
24
23
  from execnb.shell import *
@@ -77,6 +77,7 @@ class Release:
77
77
  os.chdir(self.cfg.config_path)
78
78
  if repo and '/' in repo: owner,repo = repo.split('/', 1)
79
79
  owner,repo = owner or self.cfg.user, repo or self.cfg.repo
80
+ if not owner or not repo: raise Exception("Could not infer `user`/`repo` from config: add a `Repository` key under `[project.urls]` in pyproject.toml, or pass `repo='owner/repo'`")
80
81
  token = ifnone(token, os.getenv('NBDEV_TOKEN',None))
81
82
  if not token and Path('token').exists(): token = Path('token').read_text().strip()
82
83
  token = ifnone(token, os.getenv('GITHUB_TOKEN',None))
@@ -98,7 +99,7 @@ async def changelog(self:Release,
98
99
  try: self.commit_date = (lr:=await self.gh.repos.get_latest_release()).published_at
99
100
  except APIError as e:
100
101
  if e.status_code != 404: raise
101
- lr,self.commit_date = None,'2000-01-01T00:00:004Z'
102
+ lr,self.commit_date = None,'2000-01-01T00:00:00Z'
102
103
  if lr:
103
104
  run('git fetch --tags --quiet')
104
105
  _check_changelog_base(lr.tag_name)
@@ -355,14 +356,16 @@ def chk_conda_rel(
355
356
  @call_parse
356
357
  def release_pypi(
357
358
  repository:str="pypi", # Respository to upload to (defined in ~/.pypirc)
358
- quiet:bool=False # Reduce output verbosity
359
+ quiet:bool=False, # Reduce output verbosity
360
+ verbose:bool=False # Pass --verbose to twine upload
359
361
  ):
360
362
  "Create and upload Python package to PyPI"
361
363
  _dir = get_config().lib_path.parent
362
364
  q = ' --quiet' if quiet else ''
363
365
  p = ' --disable-progress-bar' if quiet else ''
364
366
  system(f'cd {_dir} && rm -rf dist build && python -m build{q}')
365
- system(f'twine upload --repository {repository}{p} {_dir}/dist/*')
367
+ v = ' --verbose' if verbose else ''
368
+ system(f'twine upload{v} --repository {repository}{p} {_dir}/dist/*')
366
369
 
367
370
  # %% ../nbs/api/18_release.ipynb #06edfcb0
368
371
  @call_parse
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nbdev
3
- Version: 3.3.4
3
+ Version: 3.3.6
4
4
  Summary: Create delightful software with Jupyter Notebooks
5
5
  Author-email: "Jeremy Howard and the fast.ai community" <j@fast.ai>
6
6
  License: Apache-2.0
@@ -16,7 +16,7 @@ Classifier: License :: OSI Approved :: Apache Software License
16
16
  Requires-Python: >=3.10
17
17
  Description-Content-Type: text/markdown
18
18
  License-File: LICENSE
19
- Requires-Dist: fastcore>=2.1.11
19
+ Requires-Dist: fastcore>=2.2.3
20
20
  Requires-Dist: execnb>=0.2.8
21
21
  Requires-Dist: astunparse
22
22
  Requires-Dist: ghapi>=2.0.2
@@ -17,6 +17,7 @@ nbdev/imports.py
17
17
  nbdev/maker.py
18
18
  nbdev/merge.py
19
19
  nbdev/migrate.py
20
+ nbdev/moddocs.py
20
21
  nbdev/process.py
21
22
  nbdev/processors.py
22
23
  nbdev/qmd.py
@@ -1,4 +1,4 @@
1
- fastcore>=2.1.11
1
+ fastcore>=2.2.3
2
2
  execnb>=0.2.8
3
3
  astunparse
4
4
  ghapi>=2.0.2
@@ -19,7 +19,7 @@ classifiers = [
19
19
  "License :: OSI Approved :: Apache Software License",
20
20
  ]
21
21
  dynamic = ["version"]
22
- dependencies = [ "fastcore>=2.1.11", "execnb>=0.2.8", "astunparse", "ghapi>=2.0.2", "watchdog", "asttokens",
22
+ dependencies = [ "fastcore>=2.2.3", "execnb>=0.2.8", "astunparse", "ghapi>=2.0.2", "watchdog", "asttokens",
23
23
  "setuptools", "build", "fastgit>=0.0.7", "pyyaml", "tomli; python_version < '3.11'", ]
24
24
 
25
25
  [project.optional-dependencies]
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