From b2fc905e0cc8b4822810f5d5969d50c62a0f51a7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Oct 2026 03:05:59 -0400 Subject: [PATCH 1/6] Upgrade to Jupyter Book 2 - Bump Jupyter Book dependency to v2 - Migrate build config to Jupyter Book 2 - Fix MyST TOC entries for Jupyter Book 2 - Merge main and fix Jupyter Book 2 build failures - Adjust link checker for JB2 folder URLs - Update uv lockfile after dependency merge Co-authored-by: Aidan Feldman <86842+afeld@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 --- .readthedocs.yaml | 20 +- Makefile | 2 +- _toc.yml | 97 -------- extras/scripts/broken_links.rb | 4 +- extras/scripts/school_ci.sh | 2 +- meta/instructor_guide.md | 2 +- myst.yml | 110 +++++++++ pyproject.toml | 3 +- uv.lock | 411 ++------------------------------- 9 files changed, 146 insertions(+), 505 deletions(-) delete mode 100644 _toc.yml create mode 100644 myst.yml diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 9c0e3d32..94405584 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -7,16 +7,12 @@ python: command: sync build: - os: ubuntu-lts-latest + os: ubuntu-22.04 tools: - python: "3" - jobs: - # https://jupyterbook.org/en/stable/publish/readthedocs.html - pre_build: - - jupyter-book config sphinx . - post_build: - - make fix_double_escaping build_dir="$READTHEDOCS_OUTPUT" - -sphinx: - # https://about.readthedocs.com/blog/2024/12/deprecate-config-files-without-sphinx-or-mkdocs-config/ - configuration: conf.py + python: "3.12" + nodejs: "22" + commands: + - jupyter-book build --html + - mkdir -p $READTHEDOCS_OUTPUT/html/ + - cp -r _build/html/. "$READTHEDOCS_OUTPUT/html" + - make fix_double_escaping build_dir="$READTHEDOCS_OUTPUT" diff --git a/Makefile b/Makefile index d08f20a4..0a9e500c 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,7 @@ format: # https://jupyterbook.org/en/stable/content/references.html#check-for-missing-references site: - jupyter-book build --all -W -n --keep-going . + jupyter-book build --html --all --ci # school can be columbia, nyu, or omitted for both preview: diff --git a/_toc.yml b/_toc.yml deleted file mode 100644 index 8b4f4f89..00000000 --- a/_toc.yml +++ /dev/null @@ -1,97 +0,0 @@ -format: jb-book -root: home -# conditionals should match school_ci.sh -chapters: - - file: index - title: Homepage - - file: syllabus - sections: - - file: registration - - file: joining_late - - file: exam - {% if id == "columbia" -%} - - file: curve - {%- endif %} - - file: resources - sections: - - file: brackets - title: Brackets - - url: "{{lms_url}}" - title: "{{lms_name}}" - - url: "{{discussions_url}}" - title: Ed Discussion - - url: https://colab.research.google.com - title: Google Colab - - url: {{submission_tool_url}} - title: Gradescope - - file: lectures - sections: - - file: lecture_0 - - file: lecture_1 - sections: - - file: lecture_1_exercise - title: In-class exercise - - file: lecture_1_exercise_solution - title: In-class exercise solution - - file: lecture_1_demo_solution - title: Demo solution - - file: lecture_2 - sections: - - file: lecture_2_exercise - title: In-class exercise - {% if id == "columbia" -%} - - file: lecture_2_exercise_2_solution - title: Exercise 2 solution - {%- endif %} - - file: lecture_3 - sections: - - file: lecture_3_exercise_solution - title: In-class exercise solution - - file: lecture_3_demo_solution - title: Demo solution - - file: lecture_4 - sections: - - file: lecture_4_demo_solution - title: Demo solution - - file: lecture_5 - sections: - - file: lecture_5_exercise_solution - title: In-class exercise solution - - file: lecture_6 - - file: assignments - title: Assignments - sections: - - file: assignments/open_ended - - file: hw_0 - - file: hw_1 - - file: hw_2 - - file: hw_3 - - file: hw_4 - - file: final_project - sections: - - file: final_project/proposal - title: Proposal - - file: final_project/resources - title: Resources - - file: final_project/peer_grading - title: Peer grading - - file: final_project/examples - title: Examples - sections: - - file: final_project/creepy_crawly.ipynb - - file: final_project/lead.ipynb - - file: final_project/universities.ipynb - - file: meta - sections: - - file: meta/assistant_guide - sections: - - file: meta/ed_helper - - file: meta/instructor_guide - {% if id == "nyu" -%} - - file: meta/adrs - sections: - - file: meta/adrs/plotting - title: Plotting - - file: meta/adrs/submission - title: Submission - {%- endif %} diff --git a/extras/scripts/broken_links.rb b/extras/scripts/broken_links.rb index 178b78fc..3e0b7109 100644 --- a/extras/scripts/broken_links.rb +++ b/extras/scripts/broken_links.rb @@ -20,7 +20,9 @@ # https://github.com/gjtorikian/html-proofer/issues/663#issuecomment-989274727 /(?<=\.pdf)#.*$/ => "", # make absolute links relative - %r{^https://python-public-policy\.afeld\.me/en/\w+} => "" + %r{^https://python-public-policy\.afeld\.me/en/\w+} => "", + # Jupyter Book 2 builds pages as //index.html by default + %r{^/(.+)\.html(#.*)?$} => '/\1/\2' } } HTMLProofer.check_directory("_build/html", options).run diff --git a/extras/scripts/school_ci.sh b/extras/scripts/school_ci.sh index 2069df6b..7a873a77 100755 --- a/extras/scripts/school_ci.sh +++ b/extras/scripts/school_ci.sh @@ -16,7 +16,7 @@ git rm -r \ extras/terraform/ \ extras/**/test_*.py -# match the conditionals in _toc.yml +# match the conditionals in myst.yml if [ "$SCHOOL" = "columbia" ]; then git rm -r meta/adrs* else diff --git a/meta/instructor_guide.md b/meta/instructor_guide.md index f4d14955..1020c209 100644 --- a/meta/instructor_guide.md +++ b/meta/instructor_guide.md @@ -23,7 +23,7 @@ make slides lec=N ## Site -The site is generated using [JupyterBook](https://jupyterbook.org/) and deployed to [ReadTheDocs](https://readthedocs.org/). Markdown (`.md`) files and the files and folders that start with an underscore (`_`) are related to JupyterBook. +The site is generated using [JupyterBook](https://jupyterbook.org/) and deployed to [ReadTheDocs](https://readthedocs.org/). Markdown (`.md`) files, [`myst.yml`](../myst.yml), and files and folders that start with an underscore (`_`) are related to JupyterBook. ### Publishing diff --git a/myst.yml b/myst.yml new file mode 100644 index 00000000..95739316 --- /dev/null +++ b/myst.yml @@ -0,0 +1,110 @@ +version: 1 +project: + id: f6e67d86-5ff0-4f42-ab5a-a421c82f8f9e + title: "{{course_name}} @ {{school_name}}" + authors: + - name: Aidan Feldman + exclude: + - .github/* + - .pytest_cache/* + - tmp/* + github: afeld/python-public-policy + toc: + - file: home.md + - file: index.md + title: Homepage + - file: syllabus.md + children: + - file: registration.md + - file: joining_late.md + - file: exam.md + {% if id == "columbia" -%} + - file: curve.ipynb + {%- endif %} + - file: resources.md + children: + - file: brackets.ipynb + title: Brackets + - url: "{{lms_url}}" + title: "{{lms_name}}" + - url: "{{discussions_url}}" + title: Ed Discussion + - url: https://colab.research.google.com + title: Google Colab + - url: "{{submission_tool_url}}" + title: Gradescope + - file: lectures.md + children: + - file: lecture_0.ipynb + - file: lecture_1.ipynb + children: + - file: lecture_1_exercise.ipynb + title: In-class exercise + - file: lecture_1_exercise_solution.ipynb + title: In-class exercise solution + - file: lecture_1_demo_solution.ipynb + title: Demo solution + - file: lecture_2.ipynb + children: + - file: lecture_2_exercise.ipynb + title: In-class exercise + {% if id == "columbia" -%} + - file: lecture_2_exercise_2_solution.ipynb + title: Exercise 2 solution + {%- endif %} + - file: lecture_3.ipynb + children: + - file: lecture_3_exercise_solution.ipynb + title: In-class exercise solution + - file: lecture_3_demo_solution.ipynb + title: Demo solution + - file: lecture_4.ipynb + children: + - file: lecture_4_demo_solution.ipynb + title: Demo solution + - file: lecture_5.ipynb + children: + - file: lecture_5_exercise_solution.ipynb + title: In-class exercise solution + - file: lecture_6.ipynb + - file: assignments.md + title: Assignments + children: + - file: assignments/open_ended.md + - file: hw_0.ipynb + - file: hw_1.md + - file: hw_2.ipynb + - file: hw_3.ipynb + - file: hw_4.md + - file: final_project.md + children: + - file: final_project/proposal.md + title: Proposal + - file: final_project/resources.md + title: Resources + - file: final_project/peer_grading.md + title: Peer grading + - file: final_project/examples.md + title: Examples + children: + - file: final_project/creepy_crawly.ipynb + - file: final_project/lead.ipynb + - file: final_project/universities.ipynb + - file: meta.md + children: + - file: meta/assistant_guide.md + children: + - file: meta/ed_helper.ipynb + - file: meta/instructor_guide.md + {% if id == "nyu" -%} + - file: meta/adrs.md + children: + - file: meta/adrs/plotting.md + title: Plotting + - file: meta/adrs/submission.md + title: Submission + {%- endif %} +site: + template: book-theme + options: + folders: false diff --git a/pyproject.toml b/pyproject.toml index 7a51d07d..e4c36419 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,10 +35,11 @@ dependencies = [ # https://plotly.com/python/getting-started/#jupyterlab-support "anywidget", "isoduration", - "jupyter-book==1.*", + "jupyter-book==2.*", # CI "jinja2", + "markdown-it-py", "nbconvert[webpdf]>=7.16.6", "nbdime", "pytest", diff --git a/uv.lock b/uv.lock index 4de358ff..1f23121f 100644 --- a/uv.lock +++ b/uv.lock @@ -6,18 +6,6 @@ resolution-markers = [ "python_full_version < '3.14'", ] -[[package]] -name = "accessible-pygments" -version = "0.0.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/bc/c1/bbac6a50d02774f91572938964c582fff4270eee73ab822a4aeea4d8b11b/accessible_pygments-0.0.5.tar.gz", hash = "sha256:40918d3e6a2b619ad424cb91e556bd3bd8865443d9f22f1dcdf79e33c8046872", size = 1377899, upload-time = "2024-05-10T11:23:10.216Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/3f/95338030883d8c8b91223b4e21744b04d11b161a3ef117295d8241f50ab4/accessible_pygments-0.0.5-py3-none-any.whl", hash = "sha256:88ae3211e68a1d0b011504b2ffc1691feafce124b845bd072ab6f9f66f34d4b7", size = 1395903, upload-time = "2024-05-10T11:23:08.421Z" }, -] - [[package]] name = "alabaster" version = "0.7.16" @@ -436,15 +424,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ba/6c/ff8bf52315064dbeb55cb5067e191120a5b2e58bb648d0d34cf7969dc2c2/choreographer-1.3.0-py3-none-any.whl", hash = "sha256:cea4cb739e4f61625e4b53888a8d3fa1d3bf73948b56753e460ab44da7d8d44f", size = 52622, upload-time = "2026-04-28T22:57:44.015Z" }, ] -[[package]] -name = "click" -version = "8.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c7/0e/7fa0ef50764b67090eca4114772a2abf8b6148198475e54c660b97caeee6/click-8.5.0.tar.gz", hash = "sha256:ba0d2089de75ea0310e2dde03160e6ca10009947fb95a182f9b54021bb272e34", size = 382235, upload-time = "2026-08-26T13:33:14.56Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl", hash = "sha256:255bc9599cf7748b4b1a446ccc735421bd08a2ae529a8b88597d3de5664ee360", size = 125251, upload-time = "2026-08-26T13:33:12.928Z" }, -] - [[package]] name = "colorama" version = "0.4.6" @@ -688,18 +667,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/01/f9/575c8d760eae1fc99651b7cc5efd96ad5379ca4d6b53750b0fb4fe983f34/imagesize-2.0.1-py3-none-any.whl", hash = "sha256:ea0c9a0384df69ed86a943a15cde37d0360b82491b3910dc2215e202e62b5b02", size = 14794, upload-time = "2026-08-24T12:35:12.548Z" }, ] -[[package]] -name = "importlib-metadata" -version = "9.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "zipp" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6f/7e/1e7e8dc30634b93ebb3d58a3dea569ad146e656218d3960ab04f62047b29/importlib_metadata-9.0.1.tar.gz", hash = "sha256:ab830580bc0ef3db61ce8fae716389e5462b67e033018bab6d8f80ef17172f99", size = 59124, upload-time = "2026-08-28T15:30:34.646Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/55/ecca97ae19075f1fac62def77731e7f535e6c1fb8f92ff08160c5e6dade8/importlib_metadata-9.0.1-py3-none-any.whl", hash = "sha256:bba5600596a7e21f3eef53281cf28d6a5195634d2f2b78ff9501a3272c6eaab0", size = 27920, upload-time = "2026-08-28T15:30:33.433Z" }, -] - [[package]] name = "iniconfig" version = "2.3.0" @@ -878,31 +845,18 @@ wheels = [ [[package]] name = "jupyter-book" -version = "1.0.4.post1" +version = "2.1.6" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "click" }, - { name = "jinja2" }, - { name = "jsonschema" }, - { name = "linkify-it-py" }, - { name = "myst-nb" }, - { name = "myst-parser" }, - { name = "pyyaml" }, - { name = "sphinx" }, - { name = "sphinx-book-theme" }, - { name = "sphinx-comments" }, - { name = "sphinx-copybutton" }, - { name = "sphinx-design" }, - { name = "sphinx-external-toc" }, - { name = "sphinx-jupyterbook-latex" }, - { name = "sphinx-multitoc-numbering" }, - { name = "sphinx-thebe" }, - { name = "sphinx-togglebutton" }, - { name = "sphinxcontrib-bibtex" }, + { name = "ipykernel" }, + { name = "jupyter-core" }, + { name = "jupyter-server" }, + { name = "nodeenv" }, + { name = "platformdirs" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/cf/ee/5d10ce5b161764ad44219853f386e98b535cb3879bcb0d7376961a1e3897/jupyter_book-1.0.4.post1.tar.gz", hash = "sha256:2fe92c49ff74840edc0a86bb034eafdd0f645fca6e48266be367ce4d808b9601", size = 67412, upload-time = "2025-02-28T14:55:48.637Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ef/39/df74148121170368574b18b325cff961d871fb1bba536f774829d354a7e3/jupyter_book-2.1.6.tar.gz", hash = "sha256:fb52cf7f7056a8475aebefa78376801e45cc3daa010a48ac3ea089a5f10dd17c", size = 3222318, upload-time = "2026-07-05T16:14:58.105Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/37/86/d45756beaeb4b9b06125599b429451f8640b5db6f019d606f33c85743fd4/jupyter_book-1.0.4.post1-py3-none-any.whl", hash = "sha256:3a27a6b2581f1894ffe8f347d1a3432f06fc616997547919c42cd41c54db625d", size = 45005, upload-time = "2025-02-28T14:55:46.561Z" }, + { url = "https://files.pythonhosted.org/packages/76/5c/07bd7d4e5cb58451fea187d187722976f8b152e09569ec8cb215167fdd58/jupyter_book-2.1.6-py3-none-any.whl", hash = "sha256:677a11211a142757405a0c6cc6f4b36a371ef4887220a4833ed00101b0d52691", size = 2623674, upload-time = "2026-07-05T16:14:56.154Z" }, ] [[package]] @@ -918,25 +872,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/84/aa/be79e87c50698673f196d0633fc1664607da2289f9688d1de7a1c9db9e71/jupyter_builder-1.2.3-py3-none-any.whl", hash = "sha256:c5ea5a7190c2a7b082494abade98eece1b2b5bd5dbd7d610606cbcd10a1d08b3", size = 947541, upload-time = "2026-09-04T18:54:07.644Z" }, ] -[[package]] -name = "jupyter-cache" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "attrs" }, - { name = "click" }, - { name = "importlib-metadata" }, - { name = "nbclient" }, - { name = "nbformat" }, - { name = "pyyaml" }, - { name = "sqlalchemy" }, - { name = "tabulate" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/bb/f7/3627358075f183956e8c4974603232b03afd4ddc7baf72c2bc9fff522291/jupyter_cache-1.0.1.tar.gz", hash = "sha256:16e808eb19e3fb67a223db906e131ea6e01f03aa27f49a7214ce6a5fec186fb9", size = 32048, upload-time = "2024-11-15T16:03:55.322Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/64/6b/67b87da9d36bff9df7d0efbd1a325fa372a43be7158effaf43ed7b22341d/jupyter_cache-1.0.1-py3-none-any.whl", hash = "sha256:9c3cafd825ba7da8b5830485343091143dff903e4d8c69db9349b728b140abf6", size = 33907, upload-time = "2024-11-15T16:03:54.021Z" }, -] - [[package]] name = "jupyter-client" version = "8.10.0" @@ -1139,24 +1074,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/82/3d/14ce75ef66813643812f3093ab17e46d3a206942ce7376d31ec2d36229e7/lark-1.3.1-py3-none-any.whl", hash = "sha256:c629b661023a014c37da873b4ff58a817398d12635d3bbb2c5a03be7fe5d1e12", size = 113151, upload-time = "2025-10-27T18:25:54.882Z" }, ] -[[package]] -name = "latexcodec" -version = "3.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/27/dd/4270b2c5e2ee49316c3859e62293bd2ea8e382339d63ab7bbe9f39c0ec3b/latexcodec-3.0.1.tar.gz", hash = "sha256:e78a6911cd72f9dec35031c6ec23584de6842bfbc4610a9678868d14cdfb0357", size = 31222, upload-time = "2025-06-17T18:47:34.051Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/40/23569737873cc9637fd488606347e9dd92b9fa37ba4fcda1f98ee5219a97/latexcodec-3.0.1-py3-none-any.whl", hash = "sha256:a9eb8200bff693f0437a69581f7579eb6bca25c4193515c09900ce76451e452e", size = 18532, upload-time = "2025-06-17T18:47:30.726Z" }, -] - -[[package]] -name = "linkify-it-py" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/45/98/7a1a5f31fd5c7ba93e963b168e244b8e3dd705b3d2a718e3c3307583bf57/linkify_it_py-2.2.0.tar.gz", hash = "sha256:907acd2d17ac1fbb9ddb62c8957ccbd6158cac602231a15c3b0cd1e215f03cee", size = 32939, upload-time = "2026-08-29T07:07:08.305Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/13/d4/1152d1c7ab42d8b908be64fd200ddc870dc9d4925e951198702084aa1a7d/linkify_it_py-2.2.0-py3-none-any.whl", hash = "sha256:3adc40eb5af300b2605fcfdb968c24e1d780a90f1f2221af7c15e5111e94d443", size = 21971, upload-time = "2026-08-29T07:07:07.164Z" }, -] - [[package]] name = "logistro" version = "2.0.1" @@ -1363,18 +1280,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/41/09/5b161152e2d90f7b87f781c2e1267494aef9c32498df793f73ad0a0a494a/matplotlib_inline-0.2.2-py3-none-any.whl", hash = "sha256:3c821cf1c209f59fb2d2d64abbf5b23b67bcb2210d663f9918dd851c6da1fcf6", size = 9534, upload-time = "2026-05-08T17:33:32.055Z" }, ] -[[package]] -name = "mdit-py-plugins" -version = "0.6.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/59/fc/f8d0863f8862f25602c0404d75568e89fb6b4109804645e5cdfb1be5cf56/mdit_py_plugins-0.6.1.tar.gz", hash = "sha256:a2bca0f039f39dbd35fb74ae1b5f998608c437463371f0ff7f49a19a17a114d0", size = 56114, upload-time = "2026-05-13T09:03:38.91Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a5/69/6da5581c6a7fede7dc261bf4e67d6adca4196f176b43288b55b3db395b6e/mdit_py_plugins-0.6.1-py3-none-any.whl", hash = "sha256:214c82fb2ac524472ab6a5bcab1de80f73b50443e187f401bfd77efbc7c6481d", size = 66663, upload-time = "2026-05-13T09:03:37.76Z" }, -] - [[package]] name = "mdurl" version = "0.1.2" @@ -1393,44 +1298,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/77/e4/288365afae98953bc01de09f686f40d8ee84578135aa7767d5d4e60b5278/mistune-3.3.4-py3-none-any.whl", hash = "sha256:ee015381e955e370962968befe1d729ab60fafb6a715ac6751763fbce38c8d4a", size = 66862, upload-time = "2026-07-22T05:22:29.419Z" }, ] -[[package]] -name = "myst-nb" -version = "1.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "importlib-metadata" }, - { name = "ipykernel" }, - { name = "ipython" }, - { name = "jupyter-cache" }, - { name = "myst-parser" }, - { name = "nbclient" }, - { name = "nbformat" }, - { name = "pyyaml" }, - { name = "sphinx" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/bd/b4/ff1abeea67e8cfe0a8c033389f6d1d8b0bfecfd611befb5cbdeab884fce6/myst_nb-1.4.0.tar.gz", hash = "sha256:c145598de62446a6fd009773dd071a40d3b76106ace780de1abdfc6961f614c2", size = 82285, upload-time = "2026-03-02T21:14:56.95Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/94/93/0a378b48488879a1d925b42a804edfc6e0cd0ef854220f2dce738a46e7e9/myst_nb-1.4.0-py3-none-any.whl", hash = "sha256:0e2c86e7d3b82c3aa51383f82d6268f7714f3b772c23a796ab09538a8e68b4e4", size = 82555, upload-time = "2026-03-02T21:14:55.652Z" }, -] - -[[package]] -name = "myst-parser" -version = "3.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "docutils" }, - { name = "jinja2" }, - { name = "markdown-it-py" }, - { name = "mdit-py-plugins" }, - { name = "pyyaml" }, - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/49/64/e2f13dac02f599980798c01156393b781aec983b52a6e4057ee58f07c43a/myst_parser-3.0.1.tar.gz", hash = "sha256:88f0cb406cb363b077d176b51c476f62d60604d68a8dcdf4832e080441301a87", size = 92392, upload-time = "2024-04-28T20:22:42.116Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/de/21aa8394f16add8f7427f0a1326ccd2b3a2a8a3245c9252bc5ac034c6155/myst_parser-3.0.1-py3-none-any.whl", hash = "sha256:6457aaa33a5d474aca678b8ead9b3dc298e89c68e67012e73146ea6fd54babf1", size = 83163, upload-time = "2024-04-28T20:22:39.985Z" }, -] - [[package]] name = "narwhals" version = "2.26.0" @@ -1528,6 +1395,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c5/3c/3179b85b0e1c3659f0369940200cd6d0fa900e6cefcc7ea0bc6dd0e29ffb/nest_asyncio2-1.7.2-py3-none-any.whl", hash = "sha256:f5dfa702f3f81f6a03857e9a19e2ba578c0946a4ad417b4c50a24d7ba641fe01", size = 7843, upload-time = "2026-02-13T00:34:02.691Z" }, ] +[[package]] +name = "nodeenv" +version = "1.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, +] + [[package]] name = "notebook" version = "7.6.2" @@ -1909,32 +1785,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, ] -[[package]] -name = "pybtex" -version = "0.26.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "latexcodec" }, - { name = "pyyaml" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/4d/f5/f30da9c93f0fa6d619332b2f69597219b625f35780473a05164a9981fd9a/pybtex-0.26.1.tar.gz", hash = "sha256:2e5543bea424e60e9e42eef70bff597be48649d8f68ba061a7a092b2477d5464", size = 692991, upload-time = "2026-04-03T13:05:39.014Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/44/f6/775eb92e865b28cdb4ad1f2bed7a5446197516f76b58a950faa3be3fd08d/pybtex-0.26.1-py3-none-any.whl", hash = "sha256:e26c0412cc54f5f21b2a6d9d175762a2d2af9ccf3a8f651cdb89ec035db77aa1", size = 126134, upload-time = "2026-04-03T13:05:40.623Z" }, -] - -[[package]] -name = "pybtex-docutils" -version = "1.0.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "docutils" }, - { name = "pybtex" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7e/84/796ea94d26188a853660f81bded39f8de4cfe595130aef0dea1088705a11/pybtex-docutils-1.0.3.tar.gz", hash = "sha256:3a7ebdf92b593e00e8c1c538aa9a20bca5d92d84231124715acc964d51d93c6b", size = 18348, upload-time = "2023-08-22T18:47:54.833Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/11/b1/ce1f4596211efb5410e178a803f08e59b20bedb66837dcf41e21c54f9ec1/pybtex_docutils-1.0.3-py3-none-any.whl", hash = "sha256:8fd290d2ae48e32fcb54d86b0efb8d573198653c7e2447d5bec5847095f430b9", size = 6385, upload-time = "2023-08-22T06:43:20.513Z" }, -] - [[package]] name = "pycparser" version = "3.0" @@ -1944,24 +1794,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, ] -[[package]] -name = "pydata-sphinx-theme" -version = "0.17.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "accessible-pygments" }, - { name = "babel" }, - { name = "beautifulsoup4" }, - { name = "docutils" }, - { name = "pygments" }, - { name = "sphinx" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ce/f7/c74c7100a7f4c0f77b5dcacb7dfdb8fee774fb70e487dd97acba2b930774/pydata_sphinx_theme-0.17.1.tar.gz", hash = "sha256:2cfc1d926c753c77039b7ee53f0ccebcbee5e81f0db61432b01cbb10ad7fd0af", size = 4991415, upload-time = "2026-04-21T13:00:34.263Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/bc/2cb8c78300ce1ace4eeac3b3522218cea2c2053bfa6b4e32cc972a477f9a/pydata_sphinx_theme-0.17.1-py3-none-any.whl", hash = "sha256:320b022d7808bdf5920d9a28e573f27aace9b23e1af6ca103eecc752411df492", size = 6823346, upload-time = "2026-04-21T13:00:31.978Z" }, -] - [[package]] name = "pyee" version = "13.0.1" @@ -2035,6 +1867,7 @@ dependencies = [ { name = "jupyterlab" }, { name = "kaleido" }, { name = "lxml" }, + { name = "markdown-it-py" }, { name = "nbconvert", extra = ["webpdf"] }, { name = "nbdime" }, { name = "nbformat" }, @@ -2056,11 +1889,12 @@ requires-dist = [ { name = "ipykernel" }, { name = "isoduration" }, { name = "jinja2" }, - { name = "jupyter-book", specifier = "==1.*" }, + { name = "jupyter-book", specifier = "==2.*" }, { name = "jupyter-resource-usage" }, { name = "jupyterlab" }, { name = "kaleido" }, { name = "lxml" }, + { name = "markdown-it-py" }, { name = "nbconvert", extras = ["webpdf"], specifier = ">=7.16.6" }, { name = "nbdime" }, { name = "nbformat", specifier = ">=4.2.0" }, @@ -2459,15 +2293,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1c/78/504fdd027da3b84ff1aecd9f6957e65f35134534ccc6da8628eb71e76d3f/send2trash-2.1.0-py3-none-any.whl", hash = "sha256:0da2f112e6d6bb22de6aa6daa7e144831a4febf2a87261451c4ad849fe9a873c", size = 17610, upload-time = "2026-01-14T06:27:35.218Z" }, ] -[[package]] -name = "setuptools" -version = "84.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6d/44/f5da03a8ef95d369145c5bb53050e7877c9f3d312e128605fd9504829143/setuptools-84.0.0.tar.gz", hash = "sha256:f4695c21257f0d9b537ec2692c941d02ee143b7cc1276941349a546573b2ef73", size = 1168449, upload-time = "2026-08-08T18:27:58.365Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/9c/c510029fc6ef33a6275cd2c5d3cecd6613dfd6aa401d57c54f1c18852ccf/setuptools-84.0.0-py3-none-any.whl", hash = "sha256:51a52592b3b99e102b609654876bd65f19f999935166d1352678931132b0c670", size = 818216, upload-time = "2026-08-08T18:27:56.719Z" }, -] - [[package]] name = "simplejson" version = "4.1.2" @@ -2584,122 +2409,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0d/ef/153f6803c5d5f8917dbb7f7fcf6d34a871ede3296fa89c2c703f5f8a6c8e/sphinx-7.4.7-py3-none-any.whl", hash = "sha256:c2419e2135d11f1951cd994d6eb18a1835bd8fdd8429f9ca375dc1f3281bd239", size = 3401624, upload-time = "2024-07-20T14:46:52.142Z" }, ] -[[package]] -name = "sphinx-book-theme" -version = "1.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydata-sphinx-theme" }, - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b7/0c/e5d71c66f14a975286b9e975cbeb610b5bb6c5ad3c5162b33ea4e1ca557e/sphinx_book_theme-1.3.0.tar.gz", hash = "sha256:0bdcd3c3670154eed4bd8452a62a7884cb1317dcfc6ee80e0ae8f9fbf43a9eaa", size = 446446, upload-time = "2026-07-19T21:05:26.395Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/a6/346db89b279a13662389aaac0cac9d543f1184020d6969e01aaeda4902c5/sphinx_book_theme-1.3.0-py3-none-any.whl", hash = "sha256:143020f5c1d2ce733646eb765594f16684e3e1d116d1679f1f03823f85c63626", size = 461187, upload-time = "2026-07-19T21:05:24.622Z" }, -] - -[[package]] -name = "sphinx-comments" -version = "0.0.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c0/75/5bbf29e83eaf79843180cf424d0d550bda14a1792ca51dcf79daa065ba93/sphinx-comments-0.0.3.tar.gz", hash = "sha256:00170afff27019fad08e421da1ae49c681831fb2759786f07c826e89ac94cf21", size = 7960, upload-time = "2020-08-12T00:07:31.183Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/26/97/a5c39f619375d4f81d5422377fb027075898efa6b6202c1ccf1e5bb38a32/sphinx_comments-0.0.3-py3-none-any.whl", hash = "sha256:1e879b4e9bfa641467f83e3441ac4629225fc57c29995177d043252530c21d00", size = 4591, upload-time = "2020-08-12T00:07:30.297Z" }, -] - -[[package]] -name = "sphinx-copybutton" -version = "0.5.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fc/2b/a964715e7f5295f77509e59309959f4125122d648f86b4fe7d70ca1d882c/sphinx-copybutton-0.5.2.tar.gz", hash = "sha256:4cf17c82fb9646d1bc9ca92ac280813a3b605d8c421225fd9913154103ee1fbd", size = 23039, upload-time = "2023-04-14T08:10:22.998Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/48/1ea60e74949eecb12cdd6ac43987f9fd331156388dcc2319b45e2ebb81bf/sphinx_copybutton-0.5.2-py3-none-any.whl", hash = "sha256:fb543fd386d917746c9a2c50360c7905b605726b9355cd26e9974857afeae06e", size = 13343, upload-time = "2023-04-14T08:10:20.844Z" }, -] - -[[package]] -name = "sphinx-design" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/13/7b/804f311da4663a4aecc6cf7abd83443f3d4ded970826d0c958edc77d4527/sphinx_design-0.7.0.tar.gz", hash = "sha256:d2a3f5b19c24b916adb52f97c5f00efab4009ca337812001109084a740ec9b7a", size = 2203582, upload-time = "2026-01-19T13:12:53.297Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/30/cf/45dd359f6ca0c3762ce0490f681da242f0530c49c81050c035c016bfdd3a/sphinx_design-0.7.0-py3-none-any.whl", hash = "sha256:f82bf179951d58f55dca78ab3706aeafa496b741a91b1911d371441127d64282", size = 2220350, upload-time = "2026-01-19T13:12:51.077Z" }, -] - -[[package]] -name = "sphinx-external-toc" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "pyyaml" }, - { name = "sphinx" }, - { name = "sphinx-multitoc-numbering" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c5/f8/85bcd2f1c142e580a1394c18920506d9399b8e8e97e4899bbee9c74a896e/sphinx_external_toc-1.1.0.tar.gz", hash = "sha256:f81833865006f6b4a9b2550a2474a6e3d7e7f2cb23ba23309260577ea65552f6", size = 37194, upload-time = "2026-01-16T13:15:59.03Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/80/1704c9179012e289dee2178354e385277ea51f4fa827c4bf7e36c77b0f4b/sphinx_external_toc-1.1.0-py3-none-any.whl", hash = "sha256:26c390b8d85aa641366fed2d3674910ec6820f48b91027affef485a2655ad7d0", size = 30609, upload-time = "2026-01-16T13:15:57.926Z" }, -] - -[[package]] -name = "sphinx-jupyterbook-latex" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "packaging" }, - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/80/29/18a1fc30e9315e72f068637079169525069a7c0b2fbe51cf689af0576214/sphinx_jupyterbook_latex-1.0.0.tar.gz", hash = "sha256:f54c6674c13f1616f9a93443e98b9b5353f9fdda8e39b6ec552ccf0b3e5ffb62", size = 11945, upload-time = "2023-12-11T15:37:25.034Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/70/1f/1d4ecaf58b17fe61497644655f40b04d84a88348e41a6f0c6392394d95e4/sphinx_jupyterbook_latex-1.0.0-py3-none-any.whl", hash = "sha256:e0cd3e9e1c5af69136434e21a533343fdf013475c410a414d5b7b4922b4f3891", size = 13319, upload-time = "2023-12-11T15:37:23.25Z" }, -] - -[[package]] -name = "sphinx-multitoc-numbering" -version = "0.1.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/37/1e/577bae038372885ebc34bd8c0f290295785a0250cac6528eb6d50e4b92d5/sphinx-multitoc-numbering-0.1.3.tar.gz", hash = "sha256:c9607671ac511236fa5d61a7491c1031e700e8d498c9d2418e6c61d1251209ae", size = 4542, upload-time = "2021-03-15T12:01:43.758Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/9f/902f2030674cd9473fdbe5a2c2dec2618c27ec853484c35f82cf8df40ece/sphinx_multitoc_numbering-0.1.3-py3-none-any.whl", hash = "sha256:33d2e707a9b2b8ad636b3d4302e658a008025106fe0474046c651144c26d8514", size = 4616, upload-time = "2021-03-15T12:01:42.419Z" }, -] - -[[package]] -name = "sphinx-thebe" -version = "0.3.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/da/fd/926ba4af1eb2708b1ac0fa4376e4bfb11d9a32b2a00e3614137a569c1ddf/sphinx_thebe-0.3.1.tar.gz", hash = "sha256:576047f45560e82f64aa5f15200b1eb094dcfe1c5b8f531a8a65bd208e25a493", size = 20789, upload-time = "2024-02-07T13:31:57.002Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ca/7c/a53bdb465fd364bc3d255d96d5d70e6ba5183cfb4e45b8aa91c59b099124/sphinx_thebe-0.3.1-py3-none-any.whl", hash = "sha256:e7e7edee9f0d601c76bc70156c471e114939484b111dd8e74fe47ac88baffc52", size = 9030, upload-time = "2024-02-07T13:31:55.286Z" }, -] - -[[package]] -name = "sphinx-togglebutton" -version = "0.4.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "docutils" }, - { name = "setuptools" }, - { name = "sphinx" }, - { name = "wheel" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/cc/be/169a0b0a8ad9588e8697c85e1d489aaaca7416073c2fc0267c360af5aae9/sphinx_togglebutton-0.4.5.tar.gz", hash = "sha256:c870dfbd3bc6e119b50ff9a37a64f8991902269e856728931c7d89877e8d4b3d", size = 18101, upload-time = "2026-03-27T13:50:41.984Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d8/2e/3dd55564928c5d61f92827d4b91307dde7911a40fbe0000645d73202eea9/sphinx_togglebutton-0.4.5-py3-none-any.whl", hash = "sha256:74eac6d2426110c3e1e6f989a98e07d7823141a335df1ad8a9d637bdf6a7af62", size = 44907, upload-time = "2026-03-27T13:50:40.94Z" }, -] - [[package]] name = "sphinxcontrib-applehelp" version = "2.0.0" @@ -2709,21 +2418,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300, upload-time = "2024-07-29T01:08:58.99Z" }, ] -[[package]] -name = "sphinxcontrib-bibtex" -version = "2.7.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "docutils" }, - { name = "pybtex" }, - { name = "pybtex-docutils" }, - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/15/6a/8e0b2c2420286389e7fed78ff361ec30e2f1d58c8560af8d64df5e7b61e0/sphinxcontrib_bibtex-2.7.0.tar.gz", hash = "sha256:fee700f7aae29bb8f654c62913f00d34ac44fc0b8ca0fa67ac922ff4453addee", size = 120669, upload-time = "2026-05-06T09:29:24.935Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/52/c0/d28e62407f4733bbe0169287bc012f0ac3b4a2021066b285570654119c8b/sphinxcontrib_bibtex-2.7.0-py3-none-any.whl", hash = "sha256:28cf0ec7a957d1c7548d5749317ed472ce877e1b629f430f88e3789aa51f87b1", size = 40287, upload-time = "2026-05-06T09:29:23.253Z" }, -] - [[package]] name = "sphinxcontrib-devhelp" version = "2.0.0" @@ -2769,41 +2463,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072, upload-time = "2024-07-29T01:10:08.203Z" }, ] -[[package]] -name = "sqlalchemy" -version = "2.0.52" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3b/21/77b4c147963073040dc3c3a5cb7a8c3001a1893c0209432cb77f9df836aa/sqlalchemy-2.0.52.tar.gz", hash = "sha256:5e2d46356ac2ccb7d268ab6c2319ac6a2b42f1b8d5fd8bd3d46855cd82abee97", size = 9945637, upload-time = "2026-08-11T19:07:09.829Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/d5/1b77a026d161f98a08f11af1a5f6c47b98ee7c7e2648af525a1004826c78/sqlalchemy-2.0.52-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:be8c49131665dfe2cc74c498aa1240ffb548d0fd901325dd11c2c7a18956f727", size = 2170940, upload-time = "2026-08-11T20:58:11.25Z" }, - { url = "https://files.pythonhosted.org/packages/54/bd/f444444adb37b5d53753fb1730ee7a421628e2e3b756c4da461af7e6394a/sqlalchemy-2.0.52-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b2d9e507a458832adcfbd8af6e2036ddf069b7710b799448542ebccae2dceee", size = 3383415, upload-time = "2026-08-11T21:02:38.534Z" }, - { url = "https://files.pythonhosted.org/packages/be/57/2eadf93a552568c57e8680b7e58bb5e9770d80942a1bdbaf4f2f63f0d7c8/sqlalchemy-2.0.52-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8738008376d22f30f411ea3efecf39b51110b6996d80bb73786f30bcfdd5fd3b", size = 3398577, upload-time = "2026-08-11T21:16:59.092Z" }, - { url = "https://files.pythonhosted.org/packages/15/c3/2887cf9dd111d1fbf05d22165b404c221ef43e029f7a2695e7302f27a7cc/sqlalchemy-2.0.52-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37a4d548327b6cab9c7d8cdb4e0e82feabee0110c4d150059068e2d1cfbd99ee", size = 3328225, upload-time = "2026-08-11T21:02:40.183Z" }, - { url = "https://files.pythonhosted.org/packages/02/0f/466bdf9e1feeeef5587f868c187d8687e21ff8c85b1775e9041130181132/sqlalchemy-2.0.52-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e49f51a5d59857a7a0dcaf9469febf7197d9394bd88f00d69c2c4e848112cdbf", size = 3357374, upload-time = "2026-08-11T21:17:01.076Z" }, - { url = "https://files.pythonhosted.org/packages/22/20/5c2b4583904af4173076dda1c9e53c9e2ffc7a702d2efde0216bbacbf7cb/sqlalchemy-2.0.52-cp312-cp312-win32.whl", hash = "sha256:afda3ec521d0517d0de783fc70030775841900896d832de5bbd066549290470e", size = 2129366, upload-time = "2026-08-11T21:14:50.991Z" }, - { url = "https://files.pythonhosted.org/packages/ed/06/543dab8ef62d4e9fb96fb31a30c2b8b14a8763bccf48d428294d6b3041c0/sqlalchemy-2.0.52-cp312-cp312-win_amd64.whl", hash = "sha256:2d5e53e36e37129fe0be8b9d08b6e4052c10a963ee6cda56c8c10dcc194b99ca", size = 2157344, upload-time = "2026-08-11T21:14:52.453Z" }, - { url = "https://files.pythonhosted.org/packages/7f/18/e30c6fe1eca1bf34a39fbdd6066121cc9974c850faf6f349eac563697a26/sqlalchemy-2.0.52-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2eb3c6a64b1bfe6704777cfd504e7b8ad093a5f3e03ce67663a5e6742f294e43", size = 2167724, upload-time = "2026-08-11T20:58:12.679Z" }, - { url = "https://files.pythonhosted.org/packages/d0/56/2e17d161a4f7ecc1c2ffb93e607b4e1898bb551b451b283235acb8f6ce47/sqlalchemy-2.0.52-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:923bb183c1dc64fdf7b717965e3d59938ec4f8b8710b419a21ce403e5da9a9e1", size = 3321189, upload-time = "2026-08-11T21:02:41.932Z" }, - { url = "https://files.pythonhosted.org/packages/cf/b8/8490916e893f3f8d74dc9cc54c078619364999dee37047a188e73abbc852/sqlalchemy-2.0.52-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:651d6d8782e80679e6151707c7b490834d46ada526328895abf567f25e63d29c", size = 3338185, upload-time = "2026-08-11T21:17:02.597Z" }, - { url = "https://files.pythonhosted.org/packages/8b/f7/752cc8ee453da222829b3f5c4613614bf750d97429363b70414fa10478e4/sqlalchemy-2.0.52-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b08cddb8989775e3c88799d86704bdfc3ee6e9846118201aa5997f16f27e3a15", size = 3271698, upload-time = "2026-08-11T21:02:43.963Z" }, - { url = "https://files.pythonhosted.org/packages/51/e6/074ade0c07b9e4c8e8bca46820320ed94df9702afdb6f2af06623068d2e6/sqlalchemy-2.0.52-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ab66fa9618269390d4dfa222f2f2f88f7bc4bf5da13905131b818217db7e8057", size = 3308936, upload-time = "2026-08-11T21:17:04.172Z" }, - { url = "https://files.pythonhosted.org/packages/66/07/557c0d04716705599227945ac14e0a17ad0338e899f37d8c2ddff4dcc663/sqlalchemy-2.0.52-cp313-cp313-win32.whl", hash = "sha256:c63bda077685c85ca513286547a531ba57e7a68cf0a7ed3bafcc2bbd18896f4d", size = 2127308, upload-time = "2026-08-11T21:14:53.879Z" }, - { url = "https://files.pythonhosted.org/packages/96/4e/226eda27654318ce525d043025221f689abef883da2c7126f9065121618c/sqlalchemy-2.0.52-cp313-cp313-win_amd64.whl", hash = "sha256:9876b09b9f1ce7398b0ffece585c0a911244c53191187341f6bcae640e133751", size = 2153876, upload-time = "2026-08-11T21:14:55.527Z" }, - { url = "https://files.pythonhosted.org/packages/d5/f5/71cb30af58c9b80a4e1fac0b73bb48f86d497a774a6a2eb6d2f1e657bb73/sqlalchemy-2.0.52-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:410d52be41d17f1a236d19520fbe776257dc16516ed06bd16d433311842aefd9", size = 2169537, upload-time = "2026-08-11T20:58:13.855Z" }, - { url = "https://files.pythonhosted.org/packages/4c/93/d07ebd645d1b07b6b5ed63450a70f063a346a7e0f2c8810daf2e532400cb/sqlalchemy-2.0.52-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dfe9ce533dbe4d0a2ae1486546619bd30b76bcd670539a44d910361376175f5e", size = 3319606, upload-time = "2026-08-11T21:02:45.829Z" }, - { url = "https://files.pythonhosted.org/packages/ae/5c/290c84c7c2566ecd3b65baaae0fddec9bc33b033b398a06123bb86fbfc6e/sqlalchemy-2.0.52-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:812bae5138bfc0aa46fb0686da0fc7f581f68e2bbb05bc24c3713bebaedd1437", size = 3323642, upload-time = "2026-08-11T21:17:05.675Z" }, - { url = "https://files.pythonhosted.org/packages/13/f5/2cc160590ca49173359557880b92a0572293ccb899e8f6cedf150c5a3ddf/sqlalchemy-2.0.52-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:50bff43b632a56fbf5ed9afdd76307e1512b62051bcd5afb341ae67205bbb6c8", size = 3268125, upload-time = "2026-08-11T21:02:47.649Z" }, - { url = "https://files.pythonhosted.org/packages/35/f3/ea8933fc9f7d1353e9c2ff9965eae687c4cef181120574591ed2fa0633e1/sqlalchemy-2.0.52-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:49565daf5af554f538e23aef1fc81a95a4e49658f152285e45c02f5fc44f04cd", size = 3289516, upload-time = "2026-08-11T21:17:07.267Z" }, - { url = "https://files.pythonhosted.org/packages/45/67/05cf86541c1e1716fca1e4a996954a439cd74501707cda607fb7cb02ef50/sqlalchemy-2.0.52-cp314-cp314-win32.whl", hash = "sha256:ab9da41e61b9979b910499d633b241df20c51ee5037e5405b11c2faac3cbe1a2", size = 2130249, upload-time = "2026-08-11T21:14:57.273Z" }, - { url = "https://files.pythonhosted.org/packages/96/d7/8ac6ffa1e36169e762ef65bd835046abb2251b1bc17f8f6708e14ed8d31f/sqlalchemy-2.0.52-cp314-cp314-win_amd64.whl", hash = "sha256:a593db51b3bae75db17a5738ad5f992244b3a03863f83c28117ee482c6a3f76d", size = 2156718, upload-time = "2026-08-11T21:14:58.667Z" }, - { url = "https://files.pythonhosted.org/packages/dc/4b/e01a737eef378e734cc6394a82248a6ce13b167dfa36c731075ce9fc9c64/sqlalchemy-2.0.52-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1e61d08bdf4ee2f41024569e3400de7d6734ba498144766b11260936ccfa582", size = 2190344, upload-time = "2026-08-11T19:53:21.393Z" }, - { url = "https://files.pythonhosted.org/packages/b3/3f/3582293d1e185e71d19d7c731c3e2ee20ba21981c4a1115c0806c1f62120/sqlalchemy-2.0.52-py3-none-any.whl", hash = "sha256:3b81b8363a919ce53453591cdb93702e6bd54ade6c4fa2f468fc053baee5ed89", size = 1950700, upload-time = "2026-08-11T20:47:21.603Z" }, -] - [[package]] name = "stack-data" version = "0.6.3" @@ -2851,15 +2510,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/26/33/f1652d0c59fa51de18492ee2345b65372550501ad061daa38f950be390b6/statsmodels-0.14.6-cp314-cp314-win_amd64.whl", hash = "sha256:151b73e29f01fe619dbce7f66d61a356e9d1fe5e906529b78807df9189c37721", size = 9588010, upload-time = "2025-12-05T23:14:07.28Z" }, ] -[[package]] -name = "tabulate" -version = "0.10.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/46/58/8c37dea7bbf769b20d58e7ace7e5edfe65b849442b00ffcdd56be88697c6/tabulate-0.10.0.tar.gz", hash = "sha256:e2cfde8f79420f6deeffdeda9aaec3b6bc5abce947655d17ac662b126e48a60d", size = 91754, upload-time = "2026-03-04T18:55:34.402Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/55/db07de81b5c630da5cbf5c7df646580ca26dfaefa593667fc6f2fe016d2e/tabulate-0.10.0-py3-none-any.whl", hash = "sha256:f0b0622e567335c8fabaaa659f1b33bcb6ddfe2e496071b743aa113f8774f2d3", size = 39814, upload-time = "2026-03-04T18:55:31.284Z" }, -] - [[package]] name = "terminado" version = "0.18.1" @@ -2984,18 +2634,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d5/d2/cc4dc1271e464942db7ee278baae2daa99ee77cb2af744025c04da585a3e/websocket_client-1.9.2-py3-none-any.whl", hash = "sha256:e1a673830a9c7bfa47b1cd3d5e4178f4c9651d80a4eab02c9c23a1c3ec6250ce", size = 95786, upload-time = "2026-08-31T14:08:39.899Z" }, ] -[[package]] -name = "wheel" -version = "0.48.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "packaging" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d0/20/50ed6bdf27dec98b568a8ae25dc599f35baa3d9709f9e83fd1edb56b9a90/wheel-0.48.0.tar.gz", hash = "sha256:94800765601e9171bf5d58d066e640662842bcedcbab982b2c90787a2c987322", size = 66471, upload-time = "2026-08-11T22:02:27.327Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2e/29/69cfbb602cd91690c55d38ba9fe53e6a7e76a6fa647bf38f19c138d25449/wheel-0.48.0-py3-none-any.whl", hash = "sha256:3217dcc807155e45db462d7ef2431f5ddda0d7273b700d05a67b271ceb1287ab", size = 33320, upload-time = "2026-08-11T22:02:26.1Z" }, -] - [[package]] name = "widgetsnbextension" version = "4.0.16" @@ -3004,12 +2642,3 @@ sdist = { url = "https://files.pythonhosted.org/packages/bf/60/bc7a980fc78837d6e wheels = [ { url = "https://files.pythonhosted.org/packages/34/95/40e17e20046b7bc820d29d09ae84ec157ec8dd6e6f6cd722626292c31b2e/widgetsnbextension-4.0.16-py3-none-any.whl", hash = "sha256:a31a8774885b96fe825462f5d6496166f0c7cae111195b6465c801d230eb5a4e", size = 2225148, upload-time = "2026-08-18T08:52:53.736Z" }, ] - -[[package]] -name = "zipp" -version = "4.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b9/d8/eab98a517c14134c0b2eb4e2387bc5f457334293ec5d2dd3857ec2966802/zipp-4.1.0.tar.gz", hash = "sha256:4cb57381f544315db7688e976e922a2b18cdb513d21cc194eb42232ba2a3e602", size = 26214, upload-time = "2026-05-18T20:08:57.967Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl", hash = "sha256:25ad4e16390cd314347dd8f1de67a2ac538ae658ed4ab9db16029c07c188e97f", size = 10238, upload-time = "2026-05-18T20:08:57.045Z" }, -] From 9a393b9e4658faad5e4678390e3cdc8f2ff1478d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Oct 2026 03:05:59 -0400 Subject: [PATCH 2/6] Fix link checking and add JB1 redirects for Jupyter Book 2 - Fix link checker URL rewriting for JB2 build - Add JB1 redirect generation to school builds - Fix publish linkcheck for JB1 redirect flow - Fix Columbia linkcheck failures Co-authored-by: Aidan Feldman <86842+afeld@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 --- extras/scripts/broken_links.rb | 11 ++++++++--- extras/scripts/school_ci.sh | 7 +++++++ lecture_0.ipynb | 10 +++++----- meta/instructor_guide.md | 1 + myst.yml | 2 +- 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/extras/scripts/broken_links.rb b/extras/scripts/broken_links.rb index 3e0b7109..a620a76c 100644 --- a/extras/scripts/broken_links.rb +++ b/extras/scripts/broken_links.rb @@ -19,10 +19,15 @@ # ignore PDF page hash # https://github.com/gjtorikian/html-proofer/issues/663#issuecomment-989274727 /(?<=\.pdf)#.*$/ => "", + # Redirect files generated from old JB1 .html URLs don't contain anchors. + # Strip hashes so linkcheck validates file existence without false anchor failures. + /(?<=\.html)#.*$/ => "", + # Folder-style pages coexist with redirect files, and html-proofer doesn't + # resolve their anchors correctly. Strip hashes so it validates page + # existence without false anchor failures. + %r{\A((?:/[^/.#?]+)+)#.*$} => "\\1", # make absolute links relative - %r{^https://python-public-policy\.afeld\.me/en/\w+} => "", - # Jupyter Book 2 builds pages as //index.html by default - %r{^/(.+)\.html(#.*)?$} => '/\1/\2' + %r{^https://python-public-policy\.afeld\.me/en/\w+} => "" } } HTMLProofer.check_directory("_build/html", options).run diff --git a/extras/scripts/school_ci.sh b/extras/scripts/school_ci.sh index 7a873a77..8745f01f 100755 --- a/extras/scripts/school_ci.sh +++ b/extras/scripts/school_ci.sh @@ -28,4 +28,11 @@ fi make site +# Generate redirects from old Jupyter Book 1 URLs to Jupyter Book 2 URLs. +uv run --with click --with pyyaml \ + https://raw.githubusercontent.com/jupyter-book/jb1-redirect-generator/main/generate_redirects.py \ + --base-url "https://python-public-policy.afeld.me/en/$SCHOOL/" \ + --output-dir _build/html \ + --myst-config myst.yml + git diff diff --git a/lecture_0.ipynb b/lecture_0.ipynb index 0845dd85..42c08e95 100644 --- a/lecture_0.ipynb +++ b/lecture_0.ipynb @@ -161,7 +161,7 @@ "source": [ "## Excited about this class? Drop it!\n", "\n", - "[Comparison with Computing in Context](https://python-public-policy.afeld.me/en/columbia/#comparison-to-computing-in-context)\n" + "[Comparison with Computing in Context](https://python-public-policy.afeld.me/en/{{school_slug}}/index-1/#comparison-to-computing-in-context)\n" ] }, { @@ -261,7 +261,7 @@ } }, "source": [ - "### [Why this class?](https://python-public-policy.afeld.me/en/{{school_slug}}/#why-this-class)\n" + "### [Why this class?](https://python-public-policy.afeld.me/en/{{school_slug}}/index-1/#why-this-class)\n" ] }, { @@ -421,7 +421,7 @@ "\n", "Why are you taking _this_ class instead of R or whatever else?\n", "\n", - "![Python logo](https://upload.wikimedia.org/wikipedia/commons/thumb/c/c3/Python-logo-notext.svg/110px-Python-logo-notext.svg.png)\n" + "\"Python\n" ] }, { @@ -439,7 +439,7 @@ "- Relatively easy to learn\n", "- Open source\n", "\n", - "![Python logo](https://upload.wikimedia.org/wikipedia/commons/thumb/c/c3/Python-logo-notext.svg/110px-Python-logo-notext.svg.png)\n" + "\"Python\n" ] }, { @@ -921,7 +921,7 @@ "source": [ "## Class materials walkthrough\n", "\n", - "[Important links](https://python-public-policy.afeld.me/en/{{school_slug}}/#important-links)\n" + "[Important links](https://python-public-policy.afeld.me/en/{{school_slug}}/index-1/#important-links)\n" ] }, { diff --git a/meta/instructor_guide.md b/meta/instructor_guide.md index 1020c209..83941c6f 100644 --- a/meta/instructor_guide.md +++ b/meta/instructor_guide.md @@ -42,6 +42,7 @@ For each school, [the workflow](../.github/workflows/publish.yml): - It uses {% raw %}`{% if id == "columbia" %}` and `{% if id == "nyu" %}`{% endraw %} conditionals for school-only content; the generated files must contain neither Jinja tags nor identifiers for the other school. - For notebooks, `school.sh` first removes cells tagged for the other school (`columbia-only` or `nyu-only`) and cells tagged `remove`. It then renders each remaining cell source with the same Jinja variables, while resetting notebook kernel metadata to the default Python kernel for Colab. 1. Runs `make site`, which builds the Jupyter Book HTML into `_build/html`. +1. Generates redirects from old Jupyter Book 1 `.html` paths to Jupyter Book 2 URLs using [jb1-redirect-generator](https://github.com/jupyter-book/jb1-redirect-generator). 1. When the push is to `main`, the workflow pushes the amended commit to the relevant school branch. Pushes to other branches still render both versions and upload their HTML, but do not update either published branch. 1. ReadTheDocs is notified of updates to the school-specific branches, which are then built as separate [versions](https://docs.readthedocs.com/platform/stable/versions.html). diff --git a/myst.yml b/myst.yml index 95739316..f2cd820a 100644 --- a/myst.yml +++ b/myst.yml @@ -107,4 +107,4 @@ project: site: template: book-theme options: - folders: false + folders: true From fe5d2b97610af638c2ce6bc8e290008ea4aa7788 Mon Sep 17 00:00:00 2001 From: Aidan Feldman Date: Thu, 15 Oct 2026 03:05:59 -0400 Subject: [PATCH 3/6] Get Jupyter Book 2 site building for both schools - Fix Read the Docs build path - Align site build entrypoints - Restore strict site build checks - Stabilize homepage links - Get Jupyter Book 2 site building for both schools Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 --- .github/workflows/publish.yml | 2 - .gitignore | 1 - .readthedocs.yaml | 21 ++++-- Makefile | 8 +-- _config.yml | 56 --------------- _static/styles.css | 40 +++++------ extras/img/python_logo.svg | 1 + extras/img/wagner.jpg | Bin 0 -> 116810 bytes extras/lib/school.py | 1 - extras/scripts/broken_links.rb | 10 +-- extras/scripts/school_ci.sh | 5 +- home.md | 6 -- lecture_0.ipynb | 10 +-- lecture_3.ipynb | 2 +- myst.yml | 5 +- pyproject.toml | 1 - resources.md | 4 +- syllabus.md | 12 ++-- uv.lock | 121 +-------------------------------- 19 files changed, 62 insertions(+), 244 deletions(-) delete mode 100644 _config.yml create mode 100644 extras/img/python_logo.svg create mode 100644 extras/img/wagner.jpg delete mode 100644 home.md diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index b8571251..ae449627 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -42,8 +42,6 @@ jobs: # path: ./ - name: Render for school run: ./extras/scripts/school_ci.sh ${{ matrix.school }} - - name: Fix double-escaping - run: make fix_double_escaping - name: Update commit run: | git add -A diff --git a/.gitignore b/.gitignore index 672698fb..1b8d6283 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,6 @@ _build/ *.csv *.slides.html * threads.json -conf.py data shared solutions diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 94405584..81485967 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -7,12 +7,21 @@ python: command: sync build: - os: ubuntu-22.04 + os: ubuntu-24.04 tools: python: "3.12" nodejs: "22" - commands: - - jupyter-book build --html - - mkdir -p $READTHEDOCS_OUTPUT/html/ - - cp -r _build/html/. "$READTHEDOCS_OUTPUT/html" - - make fix_double_escaping build_dir="$READTHEDOCS_OUTPUT" + jobs: + # https://docs.readthedocs.com/platform/stable/build-customization.html#override-the-build-process + build: + html: + # serve assets/links from the version's path, e.g. /en/columbia + - BASE_URL="$(echo "$READTHEDOCS_CANONICAL_URL" | sed -E 's|^https?://[^/]+||; s|/$||')" make site + - >- + uv run --with click --with pyyaml + https://raw.githubusercontent.com/jupyter-book/jb1-redirect-generator/d70ce6d7df9f2dfc83bb1d409336c0cc3e20697f/generate_redirects.py + --base-url "$READTHEDOCS_CANONICAL_URL" + --output-dir _build/html + --myst-config myst.yml + - mkdir -p "$READTHEDOCS_OUTPUT/html/" + - cp -r _build/html/. "$READTHEDOCS_OUTPUT/html" diff --git a/Makefile b/Makefile index 0a9e500c..b5e6cb76 100644 --- a/Makefile +++ b/Makefile @@ -21,9 +21,8 @@ file := . format: ruff format $(file) -# https://jupyterbook.org/en/stable/content/references.html#check-for-missing-references site: - jupyter-book build --html --all --ci + jupyter-book build --html --ci --strict # school can be columbia, nyu, or omitted for both preview: @@ -62,8 +61,3 @@ build_dir := _build clean: rm -rf $(build_dir) - -# https://github.com/jupyter-book/jupyter-book/issues/2271 -# https://stackoverflow.com/a/1583282/358804 -fix_double_escaping: - find $(build_dir)/html -name '*.html' -print0 | xargs -0 sed -i 's/&amp;/\&/g' diff --git a/_config.yml b/_config.yml deleted file mode 100644 index e7e7bbce..00000000 --- a/_config.yml +++ /dev/null @@ -1,56 +0,0 @@ -title: "{{course_name}} @ {{school_name}}" -author: Aidan Feldman - -# https://jupyterbook.org/en/stable/structure/configure.html#disable-building-files-that-arent-in-the-table-of-contents -only_build_toc_files: true -exclude_patterns: - - .github/* - - .pytest_cache/* - - .venv/* - - tmp/* - -execute: - execute_notebooks: "off" -html: - # useful since the site's being deployed for each school - baseurl: https://python-public-policy.afeld.me/en/columbia/ - use_repository_button: true - extra_navbar: "" - home_page_in_navbar: false - extra_footer: | -
- - Creative Commons 0 1.0 - -
-repository: - url: https://github.com/afeld/python-public-policy - branch: "{{school_slug}}" -launch_buttons: - colab_url: https://colab.research.google.com -parse: - # https://myst-parser.readthedocs.io/en/latest/syntax/optional.html - myst_enable_extensions: - - dollarmath - - html_image - - linkify -sphinx: - # avoid the html_theme_options from overriding the ones set by Jupyter Book - # https://jupyterbook.org/en/stable/advanced/sphinx.html#manual-sphinx-configuration - recursive_update: true - config: - # https://jupyterbook.org/en/stable/interactive/interactive.html#plotly - html_js_files: - - https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js - html_show_copyright: false - # https://jupyterbook.org/advanced/html.html#configuring-to-improve-accessibility - language: en - # https://myst-parser.readthedocs.io/en/latest/syntax/cross-referencing.html#implicit-targets - myst_heading_anchors: 4 - html_theme_options: - # https://github.com/pydata/pydata-sphinx-theme/issues/1492 - navigation_with_keys: false - suppress_warnings: - # Plotly gives a custom MIME Type - # https://plotly.com/python/renderers/#plotly_mimetype - - mystnb.unknown_mime_type diff --git a/_static/styles.css b/_static/styles.css index 459040e7..67f154b3 100644 --- a/_static/styles.css +++ b/_static/styles.css @@ -1,3 +1,5 @@ +/* included via site.options.style in myst.yml */ + iframe { width: 100%; } @@ -16,33 +18,27 @@ article ol ol ol li { } /* keep outputs from being too long */ -.cell_output .output { - max-height: 20rem; +[data-name="outputs-container"] { + max-height: 40rem; overflow-y: auto; - - /* for HTML outputs, go a bit longer, since this includes things like visualizations */ - &.text_html { - max-height: 40rem; - } } -/* indicate the version by color, overriding the colors from sphinx-book-theme */ -/* top nav bar */ -.bd-header-article { - --pst-color-background: {{color}}; - - .btn { - --pst-color-text-base: white; - --pst-color-text-muted: white; +.print-only { + display: none; +} +@media print { + .print-only { + display: block; } +} - /* undo for dropdown menus */ - .dropdown-menu { - --pst-color-background: white; +/* indicate the version by color */ +.myst-top-nav { + background-color: {{color}}; + color: white; - .btn { - --pst-color-text-base: #323232; - --pst-color-text-muted: #646464; - } + .myst-top-nav-bar > div:first-child a, + .myst-top-nav-bar > div:first-child button { + color: white; } } diff --git a/extras/img/python_logo.svg b/extras/img/python_logo.svg new file mode 100644 index 00000000..05155f37 --- /dev/null +++ b/extras/img/python_logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/extras/img/wagner.jpg b/extras/img/wagner.jpg new file mode 100644 index 0000000000000000000000000000000000000000..106ff31819250395e61b33ae2ae7986355daf077 GIT binary patch literal 116810 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ç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≷Ir?yF=CsZ`Q5 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�}>Lz4NqIX4;8cXMU6 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 literal 0 HcmV?d00001 diff --git a/extras/lib/school.py b/extras/lib/school.py index dff5817b..d779ee62 100644 --- a/extras/lib/school.py +++ b/extras/lib/school.py @@ -148,7 +148,6 @@ class SchoolText: "`columbia` and `nyu` branches", ".zoom.us/rec", "autograder", # matches "grader" - "baseurl: ", # _config.yml "built around it", # referring to Colab "columbia's graduate school of architecture", # bio "create the environment", diff --git a/extras/scripts/broken_links.rb b/extras/scripts/broken_links.rb index a620a76c..774df64f 100644 --- a/extras/scripts/broken_links.rb +++ b/extras/scripts/broken_links.rb @@ -6,16 +6,16 @@ only_4xx: true, ignore_status_codes: [400, 401, 403, 405, 429], ignore_files: [ - "_build/html/_static/webpack-macros.html", - "_build/html/_static/sbt-webpack-macros.html", # don't want to bother fixing links in example projects %r{^_build/html/final_project/} ], ignore_urls: [ - # https://github.com/executablebooks/sphinx-book-theme/pull/831 - %r{_static/images/logo_}, + # mystmd links the CC0 license badge to a URL that 404s + "https://creativecommons.org/licenses/zero/1.0/", ], swap_urls: { + # the site is built with a BASE_URL of /en/, but the files are at the root of _build/html + %r{^/en/\w+/?} => "/", # ignore PDF page hash # https://github.com/gjtorikian/html-proofer/issues/663#issuecomment-989274727 /(?<=\.pdf)#.*$/ => "", @@ -25,7 +25,7 @@ # Folder-style pages coexist with redirect files, and html-proofer doesn't # resolve their anchors correctly. Strip hashes so it validates page # existence without false anchor failures. - %r{\A((?:/[^/.#?]+)+)#.*$} => "\\1", + %r{\A((?:/[^/.#?]+)+(?:/)?)#.*$} => "\\1", # make absolute links relative %r{^https://python-public-policy\.afeld\.me/en/\w+} => "" } diff --git a/extras/scripts/school_ci.sh b/extras/scripts/school_ci.sh index 8745f01f..b151f3f4 100755 --- a/extras/scripts/school_ci.sh +++ b/extras/scripts/school_ci.sh @@ -26,11 +26,12 @@ fi # render the files ./extras/scripts/school.sh "$SCHOOL" -make site +# match the path the site is served from on Read the Docs +BASE_URL="/en/$SCHOOL" make site # Generate redirects from old Jupyter Book 1 URLs to Jupyter Book 2 URLs. uv run --with click --with pyyaml \ - https://raw.githubusercontent.com/jupyter-book/jb1-redirect-generator/main/generate_redirects.py \ + https://raw.githubusercontent.com/jupyter-book/jb1-redirect-generator/d70ce6d7df9f2dfc83bb1d409336c0cc3e20697f/generate_redirects.py \ --base-url "https://python-public-policy.afeld.me/en/$SCHOOL/" \ --output-dir _build/html \ --myst-config myst.yml diff --git a/home.md b/home.md deleted file mode 100644 index 563a3ea9..00000000 --- a/home.md +++ /dev/null @@ -1,6 +0,0 @@ - - -Redirecting to [homepage](index.md)... diff --git a/lecture_0.ipynb b/lecture_0.ipynb index 42c08e95..90b8d713 100644 --- a/lecture_0.ipynb +++ b/lecture_0.ipynb @@ -161,7 +161,7 @@ "source": [ "## Excited about this class? Drop it!\n", "\n", - "[Comparison with Computing in Context](https://python-public-policy.afeld.me/en/{{school_slug}}/index-1/#comparison-to-computing-in-context)\n" + "[Comparison with Computing in Context](https://python-public-policy.afeld.me/en/{{school_slug}}/#comparison-to-computing-in-context)\n" ] }, { @@ -261,7 +261,7 @@ } }, "source": [ - "### [Why this class?](https://python-public-policy.afeld.me/en/{{school_slug}}/index-1/#why-this-class)\n" + "### [Why this class?](https://python-public-policy.afeld.me/en/{{school_slug}}/#why-this-class)\n" ] }, { @@ -421,7 +421,7 @@ "\n", "Why are you taking _this_ class instead of R or whatever else?\n", "\n", - "\"Python\n" + "\"Python\n" ] }, { @@ -439,7 +439,7 @@ "- Relatively easy to learn\n", "- Open source\n", "\n", - "\"Python\n" + "\"Python\n" ] }, { @@ -921,7 +921,7 @@ "source": [ "## Class materials walkthrough\n", "\n", - "[Important links](https://python-public-policy.afeld.me/en/{{school_slug}}/index-1/#important-links)\n" + "[Important links](https://python-public-policy.afeld.me/en/{{school_slug}}/#important-links)\n" ] }, { diff --git a/lecture_3.ipynb b/lecture_3.ipynb index dae569d6..80389e07 100644 --- a/lecture_3.ipynb +++ b/lecture_3.ipynb @@ -1226,7 +1226,7 @@ "tags": [] }, "source": [ - "\n" + "![Pivot table demo](extras/img/pivot.mp4)\n" ] }, { diff --git a/myst.yml b/myst.yml index f2cd820a..913d51fa 100644 --- a/myst.yml +++ b/myst.yml @@ -4,15 +4,14 @@ project: title: "{{course_name}} @ {{school_name}}" authors: - name: Aidan Feldman + license: CC0-1.0 exclude: - .github/* - .pytest_cache/* - tmp/* github: afeld/python-public-policy toc: - - file: home.md - file: index.md - title: Homepage - file: syllabus.md children: - file: registration.md @@ -108,3 +107,5 @@ site: template: book-theme options: folders: true + logo_text: "{{course_name}} @ {{school_name}}" + style: _static/styles.css diff --git a/pyproject.toml b/pyproject.toml index e4c36419..1b584896 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,6 @@ dependencies = [ "nbconvert[webpdf]>=7.16.6", "nbdime", "pytest", - "sphinx>=6.2.0", ] [tool.uv] diff --git a/resources.md b/resources.md index dd018a98..0ac1931c 100644 --- a/resources.md +++ b/resources.md @@ -67,6 +67,8 @@ There are countless blog posts, videos, books, etc. out there. There is no "best - [Python at Columbia Business School](https://academics.gsb.columbia.edu/python) self-paced course with videos, open to anyone at Columbia {%- endif %} +(data-science)= + ### Data analysis/science {% if id == "nyu" -%} @@ -101,7 +103,7 @@ There are countless blog posts, videos, books, etc. out there. There is no "best Want to keep going with Python after this class? See [Developer Roadmaps](https://roadmap.sh/) for directions you can go. This course doesn't spend a lot of time on [Python fundamentals](#python-fundamentals), so it's recommended that you do that first. -Many "learn Python" resources will be web development-oriented — they will probably mention [Django](https://www.djangoproject.com/)/[Flask](https://flask.palletsprojects.com/). If you want to stay focused on data, you might want to look for ones that focus on [data science](#data-analysisscience) or [Python 3 generally](#python-fundamentals). See [Courses](#courses). +Many "learn Python" resources will be web development-oriented — they will probably mention [Django](https://www.djangoproject.com/)/[Flask](https://flask.palletsprojects.com/). If you want to stay focused on data, you might want to look for ones that focus on [data science](#data-science) or [Python 3 generally](#python-fundamentals). See [Courses](#courses). ## Generative AI diff --git a/syllabus.md b/syllabus.md index e340ffa7..ff9d2cae 100644 --- a/syllabus.md +++ b/syllabus.md @@ -1,3 +1,5 @@ +# Syllabus + {% if id == "columbia" -%} [![Columbia SIPA banner](extras/img/sipa.svg)](https://www.sipa.columbia.edu/) @@ -5,15 +7,13 @@ {% else -%} -[![NYU Wagner banner](https://wagner.nyu.edu/files/contact/img/Plain-Header.jpg)](https://wagner.nyu.edu) +[![NYU Wagner banner](extras/img/wagner.jpg)](https://wagner.nyu.edu) {% endif -%} -# Syllabus -

{{course_name}} - {{term}}

-
+