Try an interactive version of this dialog: Sign up at solve.it.com, click Upload, and pass this URL.
We noticed a bug with nbdev where nbdev export is too eager to replace "name" attributes in the pyproject.toml. So the example we had was that
[[tool.uv.index]] name = "pytorch-cpu" url = "https://download.pytorch.org/whl/cpu" explicit = true
was changed to:
[[tool.uv.index]] name = "project_name" url = "https://download.pytorch.org/whl/cpu" explicit = true
I prepared a pyproject.toml and a nbdev project in the folder "nbdev_demo". Can you print out the content of the toml file before and after nbdev-export?
Let me check the folder and show the toml file contents first.
view(path='nbdev_demo')
{
"id": "toolu_016NKukwmhW5zVwkMAnaM5aT",
"call": {
"function": "view",
"arguments": {
"path": "nbdev_demo"
}
},
"result": "Directory contents of /app/data/nbdev_bugfix/nbdev_demo:\n/app/data/nbdev_bugfix/nbdev_demo/nbs \ud83d\udcc1\n/app/data/nbdev_bugfix/nbdev_demo/LICENSE (11.1k)\n/app/data/nbdev_bugfix/nbdev_demo/README.md (1.3k)\n/app/data/nbdev_bugfix/nbdev_demo/pyproject.toml (0.9k)\n/app/data/nbdev_bugfix/nbdev_demo/MANIFEST.in (0.1k)\n/app/data/nbdev_bugfix/nbdev_demo/nbdev_demo \ud83d\udcc1\n/app/data/nbdev_bugfix/nbdev_demo/nbs/_quarto.yml (0.3k)\n/app/data/nbdev_bugfix/nbdev_demo/nbs/00_core.ipynb (0.9k)\n/app/data/nbdev_bugfix/nbdev_demo/nbs/styles.css (0.6k)\n/app/data/nbdev_bugfix/nbdev_demo/nbs/index.ipynb (3.5k)\n/app/data/nbdev_bugfix/nbdev_demo/nbs/nbdev.yml (0.2k)\n/app/data/nbdev_bugfix/nbdev_demo/nbdev_demo/core.py (0.2k)\n/app/data/nbdev_bugfix/nbdev_demo/nbdev_demo/__init__.py (0.0k)\n/app/data/nbdev_bugfix/nbdev_demo/nbdev_demo/_modidx.py (0.4k)"
}
view(path='nbdev_demo/pyproject.toml')
{
"id": "toolu_01Do7LiXqMEHU1MHeYEVNw9w",
"call": {
"function": "view",
"arguments": {
"path": "nbdev_demo/pyproject.toml"
}
},
"result": "[build-system]\nrequires = [\"setuptools>=64\"]\nbuild-backend = \"setuptools.build_meta\"\n\n[project]\nname = \"nbdev_demo\"\ndynamic = [\"version\"]\ndescription = \"\"\nreadme = \"README.md\"\nrequires-python = \">=3.10\"\nlicense = {text = \"Apache-2.0\"}\nauthors = [{name = \"Jonas Jakubassa\", email = \"jjakubassa@mis-analytics.de\"}]\nkeywords = ['nbdev']\nclassifiers = [\n \"Programming Language :: Python :: 3\",\n \"Programming Language :: Python :: 3 :: Only\",\n]\ndependencies = []\n\n[project.urls]\nRepository = \"https://github.com/JonasJakubassa/nbdev_demo\"\nDocumentation = \"https://JonasJakubassa.github.io/nbdev_demo/\"\n\n[project.entry-points.nbdev]\nnbdev_demo = \"nbdev_demo._modidx:d\"\n\n[tool.setuptools.dynamic]\nversion = {attr = \"nbdev_demo.__version__\"}\n\n[tool.setuptools.packages.find]\ninclude = [\"nbdev_demo\"]\n\n[tool.nbdev]\n\n[[tool.uv.index]]\nname = \"pytorch-cpu\"\nurl = \"https://download.pytorch.org/whl/cpu\"\nexplicit = true"
}
Here's the before state — note name = "pytorch-cpu" in the [[tool.uv.index]] section at the bottom.
Now let me run nbdev_export and show the file again:
run_code_interactive(code='<…>…process\nresult = subprocess.ru…')
{
"id": "toolu_019MX7rumxSDWnNG1Af8gkE2",
"call": {
"function": "run_code_interactive",
"arguments": {
"code": "import subprocess\nresult = subprocess.run(\n [\"nbdev_export\"], cwd=\"/app/data/nbdev_bugfix/nbdev_demo\", capture_output=True, text=True\n)\nprint(\"stdout:\", result.stdout)\nprint(\"stderr:\", result.stderr)\nprint(\"returncode:\", result.returncode)"
}
},
"result": "{'success': 'CRITICAL: Message added to user dialog. STOP IMMEDIATELY. Do NOT call any more tools. Wait for user to run code and respond.'}"
}
I've added a code cell that runs nbdev_export in the nbdev_demo folder. Please run it, and then I'll show the toml file contents afterwards so we can compare!
[build-system]
requires = ["setuptools>=64"]
build-backend = "setuptools.build_meta"
[project]
name = "nbdev_demo"
dynamic = ["version"]
description = ""
readme = "README.md"
requires-python = ">=3.10"
license = {text = "Apache-2.0"}
authors = [{name = "Jonas Jakubassa", email = "jjakubassa@mis-analytics.de"}]
keywords = ['nbdev']
classifiers = [
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
]
dependencies = []
[project.urls]
Repository = "https://github.com/JonasJakubassa/nbdev_demo"
Documentation = "https://JonasJakubassa.github.io/nbdev_demo/"
[project.entry-points.nbdev]
nbdev_demo = "nbdev_demo._modidx:d"
[tool.setuptools.dynamic]
version = {attr = "nbdev_demo.__version__"}
[tool.setuptools.packages.find]
include = ["nbdev_demo"]
[tool.nbdev]
[[tool.uv.index]]
name = "pytorch-cpu"
url = "https://download.pytorch.org/whl/cpu"
explicit = true[build-system]
requires = ["setuptools>=64"]
build-backend = "setuptools.build_meta"
[project]
name = "nbdev_demo"
dynamic = ["version"]
description = ""
readme = "README.md"
requires-python = ">=3.10"
license = {text = "Apache-2.0"}
authors = [{name = "Jonas Jakubassa", email = "jjakubassa@mis-analytics.de"}]
keywords = ['nbdev']
classifiers = [
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
]
dependencies = []
[project.urls]
Repository = "https://github.com/JonasJakubassa/nbdev_demo"
Documentation = "https://JonasJakubassa.github.io/nbdev_demo/"
[project.entry-points.nbdev]
nbdev_demo = "nbdev_demo._modidx:d"
[tool.setuptools.dynamic]
version = {attr = "nbdev_demo.__version__"}
[tool.setuptools.packages.find]
include = ["nbdev_demo"]
[tool.nbdev]
[[tool.uv.index]]
name = "nbdev_demo"
url = "https://download.pytorch.org/whl/cpu"
explicit = trueSo we think nbdev is only looking for the attribute "name" and not looking for the section. Can you check this in the code: https://github.com/AnswerDotAI/nbdev?
read_gh_repo(owner='AnswerDotAI', repo='nbdev')
{
"id": "toolu_01MRxmsgDosTz2hQJCbJT4rW",
"call": {
"function": "read_gh_repo",
"arguments": {
"owner": "AnswerDotAI",
"repo": "nbdev"
}
},
"result": "<TRUNCATED>\u2026tAI/nbdev\nCreate delightful software with Jupyter Notebooks\n\n## / Files\n- \ud83d\udcc1 .github\n- .gitignore\n- .pre-commit-hooks.yaml\n- CHANGELOG.md\n- CODE_OF_CONDUCT.md\n- CONTRIBUTING.md\n- LICENSE\n- MANIFEST.in\n- README.md\n- TODO.md\n- \ud83d\udcc1 nbdev\n- \ud83d\udcc1 nbs\n- pyproject.toml\n- \ud83d\udcc1 tests\n- \ud83d\udcc1 tools\n\n## README\n# Getting Started\n\n\n<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->\n\n\n\n## \ud83d\uded1**Jan 2026 Major Version Update \u2013 Breaking Change**\ud83d\uded1\n\n**nbdev3 is here!** As many of you have been requesting, configuration\nhas moved from `settings.ini` to `pyproject.toml`, following modern\nPython packaging standards ([PEP\n621](https://peps.python.org/pep-0621/)). Your project metadata now\nlives in the standard `[project]` section, while nbdev-specific settings\ngo in `[tool.nbdev]`.\n\n**Migrating from nbdev2:** Run `nbdev-migrate-config` in your project\nroot to automatically convert your `settings.ini` to `pyproject.toml`\u2026</TRUNCATED>"
}
Let me look at the nbdev source code to find where it writes to pyproject.toml:
read_gh_repo(owner='AnswerDotAI', repo='nbdev', path='nbdev')
{
"id": "toolu_01FqB1gbFLt2nu9LsVckaxex",
"call": {
"function": "read_gh_repo",
"arguments": {
"owner": "AnswerDotAI",
"repo": "nbdev",
"path": "nbdev"
}
},
"result": "# AnswerDotAI/nbdev\nCreate delightful software with Jupyter Notebooks\n\n## /nbdev Files\n- __init__.py\n- _modidx.py\n- clean.py\n- cli.py\n- config.py\n- diff.py\n- doclinks.py\n- export.py\n- extract_attachments.py\n- frontmatter.py\n- imports.py\n- maker.py\n- merge.py\n- migrate.py\n- process.py\n- processors.py\n- qmd.py\n- quarto.py\n- release.py\n- scrubmagics.py\n- serve.py\n- serve_drv.py\n- showdoc.py\n- sync.py\n- test.py"
}
read_gh_repo(owner='AnswerDotAI', repo='nbdev', path='nbdev/config.py')
{
"id": "toolu_01KqiWD7y2zCEMWAPyYXnEd2",
"call": {
"function": "read_gh_repo",
"arguments": {
"owner": "AnswerDotAI",
"repo": "nbdev",
"path": "nbdev/config.py"
}
},
"result": "---------------------------------------------------------------------------\nAttributeError Traceback (most recent call last)\nCell In[15], line 2\n 1 import asyncio\n----> 2 __8b9ea5a5 = read_gh_repo(*(), **{'owner': 'AnswerDotAI', 'repo': 'nbdev', 'path': 'nbdev/config.py'})\n 3 if asyncio.iscoroutine(__8b9ea5a5): __8b9ea5a5 = await __8b9ea5a5\n\nFile /usr/local/lib/python3.12/site-packages/ipykernel_helper/core.py:244, in read_gh_repo(owner, repo, ref, path)\n 242 ref = ref or info.default_branch\n 243 contents = api.repos.get_content(owner, repo, path or '', ref=ref)\n--> 244 files = [f\"- {'\ud83d\udcc1 ' if c.type=='dir' else ''}{c.name}\" for c in contents]\n 245 res.append(f'\\n## /{path or \"\"} Files\\n' + '\\n'.join(files))\n 246 if not path:\n\nAttributeError: 'str' object has no attribute 'type'"
}
Let me read the config.py file directly:
read_url(url='<…>…w.githubusercontent.com/Answer…', as_md=False)
{
"id": "toolu_01UXSEBdGSZUbqGxhKFLha2w",
"call": {
"function": "read_url",
"arguments": {
"url": "https://raw.githubusercontent.com/AnswerDotAI/nbdev/main/nbdev/config.py",
"as_md": "False"
}
},
"result": "<TRUNCATED>\u2026ring nbdev and bootstrapping notebook export\"\"\"\n\n# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/api/01_config.ipynb.\n\n# %% auto #0\n__all__ = ['pyproject_nm', 'pyproject_tmpl', 'nbdev_defaults', 'pyproj_tmpl', 'nbdev_create_config', 'ConfigToml', 'get_config',\n 'is_nbdev', 'create_output', 'show_src', 'read_version', 'set_version', 'bump_version', 'update_version',\n 'update_proj', 'add_init', 'import_obj', 'write_cells']\n\n# %% ../nbs/api/01_config.ipynb #6fd14ecd\nfrom datetime import datetime\nfrom fastcore.docments import *\nfrom fastcore.utils import *\nfrom fastcore.meta import *\nfrom fastcore.script import *\nfrom fastcore.style import *\nfrom fastcore.xdg import *\n\nimport ast,importlib,warnings\nfrom IPython.display import Markdown\nfrom execnb.nbio import read_nb,NbCell\nfrom urllib.error import HTTPError\n\ntry: import tomllib\nexcept ImportError: import tomli as tomllib\n\n# %% ../nbs/api/01_config.ipynb #117128e6\npyproject_nm = 'pyproject.toml'\n_n\u2026</TRUNCATED>"
}
Found it! The culprit is in config.py. Here are the key lines:
_re_proj = re.compile(r'^name\s*=\s*".*$', re.MULTILINE)
and:
def update_proj(path):
"Create or update `pyproject.toml` in the project root."
fname = path/_pyproj
if not fname.exists(): fname.write_text(pyproj_tmpl)
txt = fname.read_text()
txt = _re_proj.sub(f'name = "{get_config().lib_name}"', txt)
txt = _re_reqpy.sub(f'requires-python = ">={get_config().min_python}"', txt)
fname.write_text(txt)
The regex r'^name\s*=\s*".*$' with re.MULTILINE matches any line starting with name = "..." anywhere in the file — it doesn't limit itself to the [project] section. So _re_proj.sub(...) replaces every name attribute it finds, including the one under [[tool.uv.index]].
The same issue likely applies to _re_reqpy too — if you had a requires-python in another section, it would also get clobbered.
Would you like to work on a fix? One approach would be to make the regex section-aware (e.g., only replace within the [project] section). Another would be to use a proper TOML library to do the update. What direction are you thinking?
Good question! In practice, requires-python is pretty specific to the [project] section — it's not a standard key anywhere else in pyproject.toml. So while the regex has the same section-unaware pattern, it's unlikely to cause real problems.
name on the other hand is extremely generic — it shows up in [[tool.uv.index]], inside authors lists, potentially in [tool.poetry.source], etc. That's what makes it the real problem here.
ok, then let's fix the name regex. how to only look in the project section? make a few suggestions how to tackle this?
Here are three approaches, from simplest to most robust:
Section-bounded regex — Use a regex that matches
name = "..."only between[project]and the next[...header. Something like matching the whole[project]section and doing the substitution only within that matched group.Find section boundaries, then replace within range — Parse the file to find the line range of the
[project]section (from[project]to the next[header), then apply the existing_re_proj.sub()only on that slice of text, and stitch the file back together.Use
tomlkit— A TOML library that preserves formatting, comments, and ordering. Parse → modify → write back. Most robust, but adds a dependency.
Given that nbdev already does simple regex-based text manipulation and the fix is small, I'd lean towards option 2 as the sweet spot — minimal change, no new dependency, and it properly scopes the replacement. What do you think?
The idea is to anchor the regex to the [project] section by capturing from the [project] header up to the name line, ensuring we don't cross into another section. Something like:
_re_proj = re.compile(r'(\[project\](?:\n(?!\[).*)*?\n)name\s*=\s*"[^"]*"')
The key piece is (?:\n(?!\[).*)*? — this matches lines between [project] and name, but refuses to cross a line starting with [ (which would be a new section header). The sub call would then use \1 to preserve the captured prefix.
Does the logic make sense? Want to try wiring it into the update_proj function?
toml = """
[build-system]
requires = ["setuptools>=64"]
build-backend = "setuptools.build_meta"
[project]
name = "nbdev_demo"
dynamic = ["version"]
description = ""
readme = "README.md"
requires-python = ">=3.10"
license = {text = "Apache-2.0"}
authors = [{name = "Jonas Jakubassa", email = "jjakubassa@mis-analytics.de"}]
keywords = ['nbdev']
classifiers = [
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
]
dependencies = []
[project.urls]
Repository = "https://github.com/JonasJakubassa/nbdev_demo"
Documentation = "https://JonasJakubassa.github.io/nbdev_demo/"
[project.entry-points.nbdev]
nbdev_demo = "nbdev_demo._modidx:d"
[tool.setuptools.dynamic]
version = {attr = "nbdev_demo.__version__"}
[tool.setuptools.packages.find]
include = ["nbdev_demo"]
[tool.nbdev]
[[tool.uv.index]]
name = "pytorch-cpu"
url = "https://download.pytorch.org/whl/cpu"
explicit = true
"""
Let's test the new parts. show me that only the project part is matched with the new patttern
Try this:
import re
_re_proj = re.compile(r'(\[project\](?:\n(?!\[).*)*?\n)name\s*=\s*"[^"]*"')
print(_re_proj.findall(toml))
This should show that it only captures the [project] prefix — confirming it's matching the right name line and not the one under [[tool.uv.index]].
import re
_re_proj = re.compile(r'(\[project\](?:\n(?!\[).*)*?\n)name\s*=\s*\"[^\"]*\"')
print(_re_proj.findall(toml))
Because findall returns captured groups when the pattern contains parentheses. The group (\[project\](?:\n(?!\[).*)*?\n) captures everything before the name line — and since name is the very first key after [project], the captured prefix is just [project]\n.
The important thing is: it found exactly one match, and it's the right one. Try _re_proj.search(toml).group(0) to see the full match including the name line.
toml = """
[build-system]
requires = ["setuptools>=64"]
build-backend = "setuptools.build_meta"
[project]
dynamic = ["version"]
keywords = ['nbdev']
name = "nbdev_demo"
description = ""
readme = "README.md"
requires-python = ">=3.10"
license = {text = "Apache-2.0"}
authors = [{name = "Jonas Jakubassa", email = "jjakubassa@mis-analytics.de"}]
classifiers = [
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
]
dependencies = []
[project.urls]
Repository = "https://github.com/JonasJakubassa/nbdev_demo"
Documentation = "https://JonasJakubassa.github.io/nbdev_demo/"
[project.entry-points.nbdev]
nbdev_demo = "nbdev_demo._modidx:d"
[tool.setuptools.dynamic]
version = {attr = "nbdev_demo.__version__"}
[tool.setuptools.packages.find]
include = ["nbdev_demo"]
[tool.nbdev]
[[tool.uv.index]]
name = "pytorch-cpu"
url = "https://download.pytorch.org/whl/cpu"
explicit = true
"""
Since the prefix is captured in group 1, you use \1 to preserve it:
_re_proj.sub(r'\1name = "project_name"', toml)
This keeps everything before name intact and only replaces the name = "..." part.
'\n[build-system]\nrequires = ["setuptools>=64"]\nbuild-backend = "setuptools.build_meta"\n\n[project]\ndynamic = ["version"]\nkeywords = [\'nbdev\']\nname = "project_name"\ndescription = ""\nreadme = "README.md"\nrequires-python = ">=3.10"\nlicense = {text = "Apache-2.0"}\nauthors = [{name = "Jonas Jakubassa", email = "jjakubassa@mis-analytics.de"}]\nclassifiers = [\n "Programming Language :: Python :: 3",\n "Programming Language :: Python :: 3 :: Only",\n]\ndependencies = []\n\n[project.urls]\nRepository = "https://github.com/JonasJakubassa/nbdev_demo"\nDocumentation = "https://JonasJakubassa.github.io/nbdev_demo/"\n\n[project.entry-points.nbdev]\nnbdev_demo = "nbdev_demo._modidx:d"\n\n[tool.setuptools.dynamic]\nversion = {attr = "nbdev_demo.__version__"}\n\n[tool.setuptools.packages.find]\ninclude = ["nbdev_demo"]\n\n[tool.nbdev]\n\n[[tool.uv.index]]\nname = "pytorch-cpu"\nurl = "https://download.pytorch.org/whl/cpu"\nexplicit = true\n'Here's the updated update_proj with the new regex:
_re_proj = re.compile(r'(\[project\](?:\n(?!\[).*)*?\n)name\s*=\s*"[^"]*"')
_re_reqpy = re.compile(r'^requires-python\s*=\s*".*$', re.MULTILINE)
def update_proj(path):
"Create or update `pyproject.toml` in the project root."
fname = path/_pyproj
if not fname.exists(): fname.write_text(pyproj_tmpl)
txt = fname.read_text()
txt = _re_proj.sub(rf'\1name = "{get_config().lib_name}"', txt)
txt = _re_reqpy.sub(f'requires-python = ">={get_config().min_python}"', txt)
fname.write_text(txt)
The only two changes are:
_re_projuses the new section-aware pattern- The
.sub()call usesrf'\1name = ...'to preserve the captured prefix (and note therprefix so\1isn't interpreted as an escape)
Processing ./nbdev
Installing build dependencies ... done
Getting requirements to build wheel ... done
Preparing metadata (pyproject.toml) ... done
Requirement already satisfied: fastcore>=1.12.3 in /usr/local/lib/python3.12/site-packages (from nbdev==3.0.13) (1.12.18)
Requirement already satisfied: execnb>=0.1.12 in /usr/local/lib/python3.12/site-packages (from nbdev==3.0.13) (0.1.18)
Requirement already satisfied: astunparse in /usr/local/lib/python3.12/site-packages (from nbdev==3.0.13) (1.6.3)
Requirement already satisfied: ghapi>=1.0.3 in /usr/local/lib/python3.12/site-packages (from nbdev==3.0.13) (1.0.10)
Requirement already satisfied: watchdog in /usr/local/lib/python3.12/site-packages (from nbdev==3.0.13) (6.0.0)
Requirement already satisfied: asttokens in /usr/local/lib/python3.12/site-packages (from nbdev==3.0.13) (3.0.1)
Requirement already satisfied: setuptools in /usr/local/lib/python3.12/site-packages (from nbdev==3.0.13) (82.0.0)
Requirement already satisfied: build in /usr/local/lib/python3.12/site-packages (from nbdev==3.0.13) (1.4.0)
Requirement already satisfied: fastgit in /usr/local/lib/python3.12/site-packages (from nbdev==3.0.13) (0.0.3)
Requirement already satisfied: pyyaml in /usr/local/lib/python3.12/site-packages (from nbdev==3.0.13) (6.0.3)
Requirement already satisfied: ipython in /usr/local/lib/python3.12/site-packages (from execnb>=0.1.12->nbdev==3.0.13) (9.10.0)
Requirement already satisfied: packaging in /usr/local/lib/python3.12/site-packages (from ghapi>=1.0.3->nbdev==3.0.13) (26.0)
Requirement already satisfied: wheel<1.0,>=0.23.0 in /usr/local/lib/python3.12/site-packages (from astunparse->nbdev==3.0.13) (0.46.3)
Requirement already satisfied: six<2.0,>=1.6.1 in /usr/local/lib/python3.12/site-packages (from astunparse->nbdev==3.0.13) (1.17.0)
Requirement already satisfied: pyproject_hooks in /usr/local/lib/python3.12/site-packages (from build->nbdev==3.0.13) (1.2.0)
Requirement already satisfied: decorator>=4.3.2 in /usr/local/lib/python3.12/site-packages (from ipython->execnb>=0.1.12->nbdev==3.0.13) (5.2.1)
Requirement already satisfied: ipython-pygments-lexers>=1.0.0 in /usr/local/lib/python3.12/site-packages (from ipython->execnb>=0.1.12->nbdev==3.0.13) (1.1.1)
Requirement already satisfied: jedi>=0.18.1 in /usr/local/lib/python3.12/site-packages (from ipython->execnb>=0.1.12->nbdev==3.0.13) (0.19.2)
Requirement already satisfied: matplotlib-inline>=0.1.5 in /usr/local/lib/python3.12/site-packages (from ipython->execnb>=0.1.12->nbdev==3.0.13) (0.2.1)
Requirement already satisfied: pexpect>4.3 in /usr/local/lib/python3.12/site-packages (from ipython->execnb>=0.1.12->nbdev==3.0.13) (4.9.0)
Requirement already satisfied: prompt_toolkit<3.1.0,>=3.0.41 in /usr/local/lib/python3.12/site-packages (from ipython->execnb>=0.1.12->nbdev==3.0.13) (3.0.52)
Requirement already satisfied: pygments>=2.11.0 in /usr/local/lib/python3.12/site-packages (from ipython->execnb>=0.1.12->nbdev==3.0.13) (2.19.2)
Requirement already satisfied: stack_data>=0.6.0 in /usr/local/lib/python3.12/site-packages (from ipython->execnb>=0.1.12->nbdev==3.0.13) (0.6.3)
Requirement already satisfied: traitlets>=5.13.0 in /usr/local/lib/python3.12/site-packages (from ipython->execnb>=0.1.12->nbdev==3.0.13) (5.14.3)
Requirement already satisfied: wcwidth in /usr/local/lib/python3.12/site-packages (from prompt_toolkit<3.1.0,>=3.0.41->ipython->execnb>=0.1.12->nbdev==3.0.13) (0.6.0)
Requirement already satisfied: parso<0.9.0,>=0.8.4 in /usr/local/lib/python3.12/site-packages (from jedi>=0.18.1->ipython->execnb>=0.1.12->nbdev==3.0.13) (0.8.6)
Requirement already satisfied: ptyprocess>=0.5 in /usr/local/lib/python3.12/site-packages (from pexpect>4.3->ipython->execnb>=0.1.12->nbdev==3.0.13) (0.7.0)
Requirement already satisfied: executing>=1.2.0 in /usr/local/lib/python3.12/site-packages (from stack_data>=0.6.0->ipython->execnb>=0.1.12->nbdev==3.0.13) (2.2.1)
Requirement already satisfied: pure-eval in /usr/local/lib/python3.12/site-packages (from stack_data>=0.6.0->ipython->execnb>=0.1.12->nbdev==3.0.13) (0.2.3)
Building wheels for collected packages: nbdev
Building wheel for nbdev (pyproject.toml) ... done
Created wheel for nbdev: filename=nbdev-3.0.13-py3-none-any.whl size=75067 sha256=b9f50d1f426c7e51909e3cda0d6777bcd970a546a5ee50243d31496fd8b33eba
Stored in directory: /tmp/pip-ephem-wheel-cache-y25p52b8/wheels/9d/25/40/74bbfd6583a601e307b826c292ba36fb108709b5068e47e6ad
Successfully built nbdev
Installing collected packages: nbdev
Attempting uninstall: nbdev
Found existing installation: nbdev 3.0.13
Uninstalling nbdev-3.0.13:
Successfully uninstalled nbdev-3.0.13
Successfully installed nbdev-3.0.13
def update_proj(path):
"Create or update `pyproject.toml` in the project root."
fname = path/_pyproj
if not fname.exists(): fname.write_text(pyproj_tmpl)
txt = fname.read_text()
txt = _re_proj.sub(rf'\1name = "{get_config().lib_name}"', txt)
txt = _re_reqpy.sub(f'requires-python = ">={get_config().min_python}"', txt)
fname.write_text(txt)
File: ~/.local/lib/python3.12/site-packages/nbdev/config.py
[build-system]
requires = ["setuptools>=64"]
build-backend = "setuptools.build_meta"
[project]
name = "nbdev_demo"
dynamic = ["version"]
description = ""
readme = "README.md"
requires-python = ">=3.10"
license = {text = "Apache-2.0"}
authors = [{name = "Jonas Jakubassa", email = "jjakubassa@mis-analytics.de"}]
keywords = ['nbdev']
classifiers = [
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
]
dependencies = []
[project.urls]
Repository = "https://github.com/JonasJakubassa/nbdev_demo"
Documentation = "https://JonasJakubassa.github.io/nbdev_demo/"
[project.entry-points.nbdev]
nbdev_demo = "nbdev_demo._modidx:d"
[tool.setuptools.dynamic]
version = {attr = "nbdev_demo.__version__"}
[tool.setuptools.packages.find]
include = ["nbdev_demo"]
[tool.nbdev]
[[tool.uv.index]]
name = "pytorch-cpu"
url = "https://download.pytorch.org/whl/cpu"
explicit = true[build-system]
requires = ["setuptools>=64"]
build-backend = "setuptools.build_meta"
[project]
name = "nbdev_demo"
dynamic = ["version"]
description = ""
readme = "README.md"
requires-python = ">=3.10"
license = {text = "Apache-2.0"}
authors = [{name = "Jonas Jakubassa", email = "jjakubassa@mis-analytics.de"}]
keywords = ['nbdev']
classifiers = [
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
]
dependencies = []
[project.urls]
Repository = "https://github.com/JonasJakubassa/nbdev_demo"
Documentation = "https://JonasJakubassa.github.io/nbdev_demo/"
[project.entry-points.nbdev]
nbdev_demo = "nbdev_demo._modidx:d"
[tool.setuptools.dynamic]
version = {attr = "nbdev_demo.__version__"}
[tool.setuptools.packages.find]
include = ["nbdev_demo"]
[tool.nbdev]
[[tool.uv.index]]
name = "pytorch-cpu"
url = "https://download.pytorch.org/whl/cpu"
explicit = true