uEdition 2.0.0a1__tar.gz → 2.0.0b1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of uEdition might be problematic. Click here for more details.

Files changed (101) hide show
  1. {uedition-2.0.0a1 → uedition-2.0.0b1}/PKG-INFO +5 -2
  2. uedition-2.0.0b1/docs/en/index.md +56 -0
  3. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/pyproject.toml +5 -3
  4. uedition-2.0.0b1/docs/static/pyproject.toml +29 -0
  5. {uedition-2.0.0a1 → uedition-2.0.0b1}/pyproject.toml +16 -13
  6. {uedition-2.0.0a1 → uedition-2.0.0b1}/uedition/__about__.py +1 -1
  7. uedition-2.0.0b1/uedition/cli/__init__.py +18 -0
  8. uedition-2.0.0b1/uedition/cli/base.py +8 -0
  9. {uedition-2.0.0a1 → uedition-2.0.0b1}/uedition/cli/build.py +22 -18
  10. uedition-2.0.0b1/uedition/cli/init.py +22 -0
  11. uedition-2.0.0b1/uedition/cli/language.py +63 -0
  12. uedition-2.0.0b1/uedition/cli/migrate.py +137 -0
  13. {uedition-2.0.0a1 → uedition-2.0.0b1}/uedition/cli/serve.py +5 -2
  14. uedition-2.0.0b1/uedition/cli/update.py +84 -0
  15. {uedition-2.0.0a1 → uedition-2.0.0b1}/uedition/ext/tei/builder.py +19 -0
  16. {uedition-2.0.0a1 → uedition-2.0.0b1}/uedition/ext/tei/parser.py +18 -9
  17. uedition-2.0.0a1/docs/.uEdition.answers +0 -9
  18. uedition-2.0.0a1/docs/de/.uEdition.answers +0 -5
  19. uedition-2.0.0a1/docs/en/.uEdition.answers +0 -5
  20. uedition-2.0.0a1/docs/en/index.md +0 -70
  21. uedition-2.0.0a1/uedition/cli/__init__.py +0 -61
  22. uedition-2.0.0a1/uedition/cli/create.py +0 -10
  23. uedition-2.0.0a1/uedition/cli/language.py +0 -58
  24. uedition-2.0.0a1/uedition/cli/update.py +0 -16
  25. {uedition-2.0.0a1 → uedition-2.0.0b1}/.github/dependabot.yml +0 -0
  26. {uedition-2.0.0a1 → uedition-2.0.0b1}/.github/workflows/codestyle.yml +0 -0
  27. {uedition-2.0.0a1 → uedition-2.0.0b1}/.github/workflows/coverage.yml +0 -0
  28. {uedition-2.0.0a1 → uedition-2.0.0b1}/.github/workflows/release.yml +0 -0
  29. {uedition-2.0.0a1 → uedition-2.0.0b1}/.github/workflows/tests.yml +0 -0
  30. {uedition-2.0.0a1 → uedition-2.0.0b1}/.gitignore +0 -0
  31. {uedition-2.0.0a1 → uedition-2.0.0b1}/.pre-commit-config.yaml +0 -0
  32. {uedition-2.0.0a1 → uedition-2.0.0b1}/.readthedocs.yml +0 -0
  33. {uedition-2.0.0a1 → uedition-2.0.0b1}/LICENSE.txt +0 -0
  34. {uedition-2.0.0a1 → uedition-2.0.0b1}/README.md +0 -0
  35. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/.gitignore +0 -0
  36. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/.readthedocs.yml +0 -0
  37. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/de/changelog.md +0 -0
  38. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/de/index.md +0 -0
  39. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/de/user/configuration.md +0 -0
  40. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/de/user/content.md +0 -0
  41. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/de/user/create.md +0 -0
  42. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/de/user/index.md +0 -0
  43. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/de/user/installation.md +0 -0
  44. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/de/user/language-add.md +0 -0
  45. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/de/user/language-update.md +0 -0
  46. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/de/user/publish.md +0 -0
  47. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/de/user/update.md +0 -0
  48. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/en/changelog.md +0 -0
  49. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/en/user/configuration.md +0 -0
  50. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/en/user/content.md +0 -0
  51. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/en/user/create.md +0 -0
  52. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/en/user/index.md +0 -0
  53. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/en/user/installation.md +0 -0
  54. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/en/user/language-add.md +0 -0
  55. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/en/user/language-update.md +0 -0
  56. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/en/user/publish.md +0 -0
  57. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/en/user/update.md +0 -0
  58. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/en/user/working-with-tei.tei +0 -0
  59. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/static/overrides.css +0 -0
  60. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/toc.yml +0 -0
  61. {uedition-2.0.0a1 → uedition-2.0.0b1}/docs/uEdition.yml +0 -0
  62. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/__init__.py +0 -0
  63. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/conftest.py +0 -0
  64. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/fixtures/basic/uEdition.yml +0 -0
  65. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/fixtures/empty/.gitkeep +0 -0
  66. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/fixtures/multilang/.gitignore +0 -0
  67. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/fixtures/multilang/de/a-1-page.md +0 -0
  68. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/fixtures/multilang/de/a-2-page.md +0 -0
  69. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/fixtures/multilang/de/a-page.md +0 -0
  70. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/fixtures/multilang/de/b-page.md +0 -0
  71. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/fixtures/multilang/de/intro.md +0 -0
  72. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/fixtures/multilang/en/a-1-page.md +0 -0
  73. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/fixtures/multilang/en/a-2-page.md +0 -0
  74. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/fixtures/multilang/en/a-page.md +0 -0
  75. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/fixtures/multilang/en/b-page.md +0 -0
  76. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/fixtures/multilang/en/intro.md +0 -0
  77. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/fixtures/multilang/references.bib +0 -0
  78. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/fixtures/multilang/toc.yml +0 -0
  79. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/fixtures/multilang/uEdition.yaml +0 -0
  80. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/fixtures/yaml/uEdition.yaml +0 -0
  81. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/test_about.py +0 -0
  82. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/test_build.py +0 -0
  83. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/test_ext/test_config.py +0 -0
  84. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/test_ext/test_tei/__init__.py +0 -0
  85. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/test_ext/test_tei/test_parser.py +0 -0
  86. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/test_language.py +0 -0
  87. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/test_serve.py +0 -0
  88. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/test_settings.py +0 -0
  89. {uedition-2.0.0a1 → uedition-2.0.0b1}/tests/test_update.py +0 -0
  90. {uedition-2.0.0a1 → uedition-2.0.0b1}/tox.ini +0 -0
  91. {uedition-2.0.0a1 → uedition-2.0.0b1}/uedition/__init__.py +0 -0
  92. {uedition-2.0.0a1 → uedition-2.0.0b1}/uedition/__main__.py +0 -0
  93. {uedition-2.0.0a1 → uedition-2.0.0b1}/uedition/ext/__init__.py +0 -0
  94. {uedition-2.0.0a1 → uedition-2.0.0b1}/uedition/ext/config.py +0 -0
  95. {uedition-2.0.0a1 → uedition-2.0.0b1}/uedition/ext/language_switcher.css +0 -0
  96. {uedition-2.0.0a1 → uedition-2.0.0b1}/uedition/ext/language_switcher.js +0 -0
  97. {uedition-2.0.0a1 → uedition-2.0.0b1}/uedition/ext/language_switcher.py +0 -0
  98. {uedition-2.0.0a1 → uedition-2.0.0b1}/uedition/ext/settings.py +0 -0
  99. {uedition-2.0.0a1 → uedition-2.0.0b1}/uedition/ext/tei/__init__.py +0 -0
  100. {uedition-2.0.0a1 → uedition-2.0.0b1}/uedition/ext/tei/tei_download.js +0 -0
  101. {uedition-2.0.0a1 → uedition-2.0.0b1}/uedition/settings.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uEdition
3
- Version: 2.0.0a1
3
+ Version: 2.0.0b1
4
4
  Project-URL: Documentation, https://github.com/uEdition/uEdition#readme
5
5
  Project-URL: Issues, https://github.com/uEdition/uEdition/issues
6
6
  Project-URL: Source, https://github.com/uEdition/uEdition
@@ -16,16 +16,19 @@ Classifier: Programming Language :: Python :: 3.13
16
16
  Classifier: Programming Language :: Python :: Implementation :: CPython
17
17
  Classifier: Programming Language :: Python :: Implementation :: PyPy
18
18
  Requires-Python: >=3.10
19
- Requires-Dist: copier<10.0.0,>=9.0.0
19
+ Requires-Dist: httpx<0.29,>=0.28.1
20
20
  Requires-Dist: livereload
21
21
  Requires-Dist: lxml<6.0.0,>=4.9.2
22
22
  Requires-Dist: myst-parser<5,>=4.0.1
23
+ Requires-Dist: packaging==24.2
23
24
  Requires-Dist: pydantic-settings<3.0.0,>=2.0.0
24
25
  Requires-Dist: pydantic<3.0.0,>=2.0.0
25
26
  Requires-Dist: pyyaml<7.0.0,>=6.0.0
26
27
  Requires-Dist: sphinx-book-theme<2,>=1.1.4
27
28
  Requires-Dist: sphinx-external-toc<2,>=1.0.1
28
29
  Requires-Dist: sphinx<9,>=8.2.3
30
+ Requires-Dist: strictyaml<2,>=1.7.3
31
+ Requires-Dist: tomlkit<0.14,>=0.13.2
29
32
  Requires-Dist: typer<1.0.0
30
33
  Description-Content-Type: text/markdown
31
34
 
@@ -0,0 +1,56 @@
1
+ # μEdition
2
+
3
+ The process of creating and making available a (critical) digital edition often presents projects with a range of significant
4
+ hurdles, particularly around technical knowledge and hosting costs. The μEdition is a framwork that lowers these barriers by
5
+ providing a simple tool that supports users in easily building (multi-lingual) digital editions that can then easily be made
6
+ available online using free or low-cost hosting solutions.
7
+
8
+ :::{admonition} Getting Help
9
+ :class: tip
10
+
11
+ The μEdition is still a young project and relies on your feedback to further lower the barriers to its use. Whether this is
12
+ adding documentation on how to do things, fixing broken things, or adding extra features, please let us know what is needed
13
+ and then we can make it better.
14
+
15
+ If you have any questions about anything related to the μEdition, please use our GitHub Discussions forum to ask:
16
+ [https://github.com/uEdition/uEdition/discussions](https://github.com/uEdition/uEdition/discussions).
17
+
18
+ If you run into any bugs, then please report these via the GitHub Issues and we can get them fixed:
19
+ [https://github.com/uEdition/uEdition/issues](https://github.com/uEdition/uEdition/issues).
20
+ :::
21
+
22
+ ## Contents
23
+
24
+ :::{tableofcontents}
25
+ :::
26
+
27
+ ## Quickstart
28
+
29
+ To quickly get started with the μEdition follow these steps:
30
+
31
+ 1. Install [Hatch](https://hatch.pypa.io/latest/install/) for your operating system.
32
+ 2. Create a new folder for your μEdition.
33
+ 3. Download the default {download}`_static/pyproject.toml` and move that into your new folder.
34
+ 4. Open a new terminal, change into your new folder and run the following command:
35
+
36
+ :::{code-block} console
37
+ hatch run init
38
+ :::
39
+
40
+ This creates the configuration file ({file}`uEdition.yml`) and table of contents ({file}`toc.yml`).
41
+
42
+ 5. Then run the following command to add content in a new language:
43
+
44
+ :::{code-block} console
45
+ hatch run language add
46
+ :::
47
+
48
+ This will ask you a few questions about the new language and then create the required files.
49
+
50
+ 5. Then run the following command to start the writing server:
51
+
52
+ :::{code-block} console
53
+ hatch run serve
54
+ :::
55
+
56
+ Your new μEdition will be available at http://localhost:8000.
@@ -18,12 +18,14 @@ Issues = "https://github.com/uEdition/uEdition/-/issues"
18
18
  Source = "https://github.com/uEdition/uEdition/-"
19
19
 
20
20
  [tool.hatch.envs.default]
21
- dependencies = ["uedition>=1.3.0,<2",]
21
+ dependencies = ["uEdition<2.1,>=2.0.0a2", "uEdition_editor<2.1,>=2.0.0a2"]
22
22
  skip-install = true
23
23
 
24
24
  [tool.hatch.envs.default.scripts]
25
25
  build = "uEdition build {args}"
26
+ init = "uEdition init {args}"
26
27
  serve = "uEdition serve {args}"
27
28
  update = "uEdition update {args}"
28
- add-language = "uEdition language add {args}"
29
- update-language = "uEdition language update {args}"
29
+ migrate = "uEdition migrate {args}"
30
+ language = "uEdition language {args}"
31
+ edit = "uvicorn --port 8000 uedition_editor:app {args} {args}"
@@ -0,0 +1,29 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "edition_name"
7
+ description = "edition_title"
8
+ requires-python = ">=3.10"
9
+ keywords = []
10
+ authors = [{ name = "author_name", email = "author_email@example.com" }]
11
+ classifiers = []
12
+ dependencies = []
13
+ version = "1.0.0"
14
+
15
+ [project.urls]
16
+ Documentation = "http://edition.com"
17
+ Issues = "http://edition.com"
18
+ Source = "http://edition.com"
19
+
20
+ [tool.hatch.envs.default]
21
+ dependencies = ["uEdition<2.1,>=2.0.0a2", "uEditor<2.1,>=2.0.0a2"]
22
+ skip-install = true
23
+
24
+ [tool.hatch.envs.default.scripts]
25
+ build = "uEdition build {args}"
26
+ serve = "uEdition serve {args}"
27
+ update = "uEdition update {args}"
28
+ migrate = "uEdition migrate {args}"
29
+ language = "uEdition language {args}"
@@ -3,6 +3,22 @@ requires = ["hatchling"]
3
3
  build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
+ dependencies = [
7
+ "httpx>=0.28.1,<0.29",
8
+ "lxml>=4.9.2,<6.0.0",
9
+ "livereload",
10
+ "myst-parser>=4.0.1,<5",
11
+ "packaging==24.2",
12
+ "pydantic>=2.0.0,<3.0.0",
13
+ "pydantic-settings>=2.0.0,<3.0.0",
14
+ "PyYAML>=6.0.0,<7.0.0",
15
+ "sphinx>=8.2.3,<9",
16
+ "sphinx_external_toc>=1.0.1,<2",
17
+ "sphinx-book-theme>=1.1.4,<2",
18
+ "strictyaml>=1.7.3,<2",
19
+ "tomlkit>=0.13.2,<0.14",
20
+ "typer<1.0.0",
21
+ ]
6
22
  name = "uEdition"
7
23
  description = ''
8
24
  readme = "README.md"
@@ -20,19 +36,6 @@ classifiers = [
20
36
  "Programming Language :: Python :: Implementation :: CPython",
21
37
  "Programming Language :: Python :: Implementation :: PyPy",
22
38
  ]
23
- dependencies = [
24
- "copier>=9.0.0,<10.0.0",
25
- "lxml>=4.9.2,<6.0.0",
26
- "livereload",
27
- "myst-parser>=4.0.1,<5",
28
- "pydantic>=2.0.0,<3.0.0",
29
- "pydantic-settings>=2.0.0,<3.0.0",
30
- "PyYAML>=6.0.0,<7.0.0",
31
- "sphinx>=8.2.3,<9",
32
- "sphinx_external_toc>=1.0.1,<2",
33
- "sphinx-book-theme>=1.1.4,<2",
34
- "typer<1.0.0",
35
- ]
36
39
  dynamic = ["version"]
37
40
 
38
41
  [project.scripts]
@@ -3,4 +3,4 @@
3
3
  # SPDX-License-Identifier: MIT
4
4
  """About this package."""
5
5
 
6
- __version__ = "2.0.0a1"
6
+ __version__ = "2.0.0b1"
@@ -0,0 +1,18 @@
1
+ # SPDX-FileCopyrightText: 2023-present Mark Hall <mark.hall@work.room3b.eu>
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+ """uEdtion Command-line Tool."""
5
+
6
+ from rich import print as output
7
+
8
+ from uedition.__about__ import __version__
9
+ from uedition.cli import build, init, language, migrate, serve, update # noqa:F401
10
+ from uedition.cli.base import app
11
+ from uedition.settings import settings
12
+
13
+
14
+ @app.command()
15
+ def version() -> None:
16
+ """Output the current μEdition version."""
17
+ output(f"μEdition: {__version__}")
18
+ output(f"Configuration: {settings['version']}")
@@ -0,0 +1,8 @@
1
+ # SPDX-FileCopyrightText: 2023-present Mark Hall <mark.hall@work.room3b.eu>
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+ """The μEdition CLI base."""
5
+
6
+ import typer
7
+
8
+ app = typer.Typer()
@@ -10,6 +10,7 @@ from shutil import copytree, ignore_patterns, rmtree
10
10
 
11
11
  from yaml import safe_dump, safe_load
12
12
 
13
+ from uedition.cli.base import app
13
14
  from uedition.settings import NoConfigError, reload_settings, settings
14
15
 
15
16
  LANDING_PAGE_TEMPLATE = """\
@@ -187,18 +188,19 @@ def full_build(lang: dict) -> None:
187
188
  check=False,
188
189
  shell=False,
189
190
  )
190
- copytree(
191
- path.join("_build", lang["path"], "html"),
192
- path.join(settings["output"]["path"], lang["path"]),
193
- dirs_exist_ok=True,
194
- )
195
- if settings["output"]["tei"]:
191
+ if path.isdir(path.join("_build", lang["path"], "html")):
196
192
  copytree(
197
- path.join("_build", lang["path"], "tei"),
193
+ path.join("_build", lang["path"], "html"),
198
194
  path.join(settings["output"]["path"], lang["path"]),
199
- ignore=ignore_patterns("_sphinx_design_static"),
200
195
  dirs_exist_ok=True,
201
196
  )
197
+ if settings["output"]["tei"] and path.isdir(path.join("_build", lang["path"], "tei")):
198
+ copytree(
199
+ path.join("_build", lang["path"], "tei"),
200
+ path.join(settings["output"]["path"], lang["path"]),
201
+ ignore=ignore_patterns("_sphinx_design_static"),
202
+ dirs_exist_ok=True,
203
+ )
202
204
 
203
205
 
204
206
  def partial_build(lang: dict) -> None:
@@ -227,22 +229,24 @@ def partial_build(lang: dict) -> None:
227
229
  check=False,
228
230
  shell=False,
229
231
  )
230
- copytree(
231
- path.join("_build", lang["path"], "html"),
232
- path.join(settings["output"]["path"], lang["path"]),
233
- dirs_exist_ok=True,
234
- )
235
- if settings["output"]["tei"]:
232
+ if path.isdir(path.join("_build", lang["path"], "html")):
236
233
  copytree(
237
- path.join("_build", lang["path"], "tei"),
234
+ path.join("_build", lang["path"], "html"),
238
235
  path.join(settings["output"]["path"], lang["path"]),
239
- ignore=ignore_patterns("_sphinx_design_static"),
240
236
  dirs_exist_ok=True,
241
237
  )
238
+ if settings["output"]["tei"] and path.isdir(path.join("_build", lang["path"], "tei")):
239
+ copytree(
240
+ path.join("_build", lang["path"], "tei"),
241
+ path.join(settings["output"]["path"], lang["path"]),
242
+ ignore=ignore_patterns("_sphinx_design_static"),
243
+ dirs_exist_ok=True,
244
+ )
242
245
 
243
246
 
244
- def run() -> None:
245
- """Build the full uEdition."""
247
+ @app.command()
248
+ def build() -> None:
249
+ """Build the full μEdition."""
246
250
  if not path.exists("uEdition.yml") and not path.exists("uEdition.yaml"):
247
251
  raise NoConfigError()
248
252
  if path.exists(settings["output"]["path"]):
@@ -0,0 +1,22 @@
1
+ # SPDX-FileCopyrightText: 2023-present Mark Hall <mark.hall@work.room3b.eu>
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+ """Local server that automatically rebuilds on changes."""
5
+
6
+ from os import path
7
+
8
+ from yaml import safe_dump
9
+
10
+ from uedition.cli.base import app
11
+ from uedition.settings import NoConfigError
12
+
13
+
14
+ @app.command()
15
+ def init(force: bool = False) -> None: # noqa: ARG001 FBT001 FBT002
16
+ """Initialise a new μEdition."""
17
+ if path.exists("uEdition.yml") and path.exists("uEdition.yaml"):
18
+ raise NoConfigError()
19
+ with open("uEdition.yml", "w") as out_f:
20
+ safe_dump({"version": "2", "output": "site"}, out_f)
21
+ with open("toc.yml", "w") as out_f:
22
+ safe_dump({"format": "jb-book", "root": "index"}, out_f)
@@ -0,0 +1,63 @@
1
+ # SPDX-FileCopyrightText: 2023-present Mark Hall <mark.hall@work.room3b.eu>
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+ """The μEdition language functionality."""
5
+
6
+ import os
7
+ from typing import Annotated
8
+
9
+ from rich import print as output
10
+ from typer import Option, Typer
11
+ from yaml import safe_dump, safe_load
12
+
13
+ from uedition.cli.base import app
14
+ from uedition.settings import NoConfigError
15
+
16
+ lang_app = Typer(help="Language configuration functionality")
17
+ app.add_typer(lang_app, name="language")
18
+
19
+
20
+ @lang_app.command()
21
+ def add(
22
+ code: Annotated[str, Option(prompt="Language code")],
23
+ label: Annotated[
24
+ str,
25
+ Option(prompt="Language name"),
26
+ ],
27
+ title: Annotated[str, Option(prompt="Title")],
28
+ path: str | None = None,
29
+ ) -> None:
30
+ """Add a language."""
31
+ if path is None:
32
+ path = code
33
+ if os.path.exists("uEdition.yml"):
34
+ with open("uEdition.yml") as in_f:
35
+ config = safe_load(in_f)
36
+ elif os.path.exists("uEdition.yaml"):
37
+ with open("uEdition.yaml") as in_f:
38
+ config = safe_load(in_f)
39
+ else:
40
+ raise NoConfigError()
41
+ if "languages" not in config:
42
+ config["languages"] = []
43
+ for lang in config["languages"]:
44
+ if lang["code"] == code:
45
+ output(
46
+ "[red bold]The language code [/red bold]"
47
+ f"[cyan bold]{code}[/cyan bold]"
48
+ "[red bold] is already configured[/red bold]"
49
+ )
50
+ return
51
+ if os.path.exists(path):
52
+ output(
53
+ f"[red bold]The target path [/red bold][cyan bold]{code}[/cyan bold][red bold] already exists.[/red bold]"
54
+ )
55
+ os.mkdir(path)
56
+ config["languages"].append({"code": code, "label": label, "path": path})
57
+ if "title" not in config:
58
+ config["title"] = {}
59
+ config["title"][code] = title
60
+ with open("uEdition.yml", "w") as out_f:
61
+ safe_dump(config, out_f)
62
+ with open(os.path.join(path, "index.md"), "w") as out_f:
63
+ out_f.write(f"# {title}\n")
@@ -0,0 +1,137 @@
1
+ # SPDX-FileCopyrightText: 2023-present Mark Hall <mark.hall@work.room3b.eu>
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+ """The μEdition migration functionality."""
5
+
6
+ import os
7
+ from os import path
8
+
9
+ import tomlkit
10
+ from rich import print as output
11
+
12
+ from uedition.cli.base import app
13
+ from uedition.settings import NoConfigError
14
+
15
+
16
+ def cleanup_old_files() -> None:
17
+ """Cleanup any old files."""
18
+ # Scan for old files to remove
19
+ old_copier_files = []
20
+ old_config_files = []
21
+ for basepath, _, filenames in os.walk("."):
22
+ for filename in filenames:
23
+ if filename == ".uEdition.answers":
24
+ old_copier_files.append(path.join(basepath, filename))
25
+ elif filename in ("_config.yaml", "_config.yml"):
26
+ old_config_files.append(path.join(basepath, filename))
27
+ # Remove old copier files (v2.0.0)
28
+ if len(old_copier_files) > 0:
29
+ output(":broom: Removing old configuration answers")
30
+ for filename in old_copier_files:
31
+ os.unlink(filename)
32
+ # Remove old config files (v2.0.0)
33
+ if len(old_config_files) > 0:
34
+ output(":broom: Removing old configuration files")
35
+ for filename in old_config_files:
36
+ os.unlink(filename)
37
+
38
+
39
+ def cleanup_gitignore() -> None:
40
+ """Cleanup the gitignore."""
41
+ # Update .gitignore (v2.0.0)
42
+ if path.isfile(".gitignore"):
43
+ with open(".gitignore") as in_f:
44
+ lines = in_f.readlines()
45
+ original_length = len(lines)
46
+ lines = [line for line in lines if line.strip() not in ("_config.yml", "_config.yaml")]
47
+ found = False
48
+ for line in lines:
49
+ if line.strip() == "conf.py":
50
+ found = True
51
+ if not found or len(lines) != original_length:
52
+ output(":broom: Updating the .gitignore")
53
+ if not found:
54
+ lines.append("conf.py\n")
55
+ with open(".gitignore", "w") as out_f:
56
+ for line in lines:
57
+ out_f.write(line)
58
+
59
+
60
+ def cleanup_pyproject() -> None:
61
+ """Cleanup the pyproject file."""
62
+ if not path.exists("pyproject.toml"):
63
+ raise NoConfigError()
64
+ with open("pyproject.toml") as in_f:
65
+ pyproject = tomlkit.parse(in_f.read())
66
+ updated = False
67
+ if "tool" not in pyproject:
68
+ pyproject["tool"] = tomlkit.table()
69
+ if "hatch" not in pyproject["tool"]:
70
+ pyproject["tool"]["hatch"] = tomlkit.table()
71
+ if "envs" not in pyproject["tool"]["hatch"]:
72
+ pyproject["tool"]["hatch"]["envs"] = tomlkit.table()
73
+ if "default" not in pyproject["tool"]["hatch"]["envs"]:
74
+ pyproject["tool"]["hatch"]["envs"]["default"] = tomlkit.table()
75
+ if "scripts" not in pyproject["tool"]["hatch"]["envs"]["default"]:
76
+ pyproject["tool"]["hatch"]["envs"]["default"]["scripts"] = tomlkit.table()
77
+ updated = True
78
+ if "add-language" in pyproject["tool"]["hatch"]["envs"]["default"]["scripts"]:
79
+ del pyproject["tool"]["hatch"]["envs"]["default"]["scripts"]["add-language"]
80
+ updated = True
81
+ if "update-language" in pyproject["tool"]["hatch"]["envs"]["default"]["scripts"]:
82
+ del pyproject["tool"]["hatch"]["envs"]["default"]["scripts"]["update-language"]
83
+ updated = True
84
+ if "migrate" not in pyproject["tool"]["hatch"]["envs"]["default"]["scripts"]:
85
+ pyproject["tool"]["hatch"]["envs"]["default"]["scripts"]["migrate"] = "uEdition migrate {args}"
86
+ updated = True
87
+ if "language" not in pyproject["tool"]["hatch"]["envs"]["default"]["scripts"]:
88
+ pyproject["tool"]["hatch"]["envs"]["default"]["scripts"]["language"] = "uEdition language {args}"
89
+ updated = True
90
+ if "init" not in pyproject["tool"]["hatch"]["envs"]["default"]["scripts"]:
91
+ pyproject["tool"]["hatch"]["envs"]["default"]["scripts"]["init"] = "uEdition init {args}"
92
+ updated = True
93
+ if "edit" not in pyproject["tool"]["hatch"]["envs"]["default"]["scripts"]:
94
+ pyproject["tool"]["hatch"]["envs"]["default"]["scripts"]["edit"] = (
95
+ "uvicorn --port 8000 uedition_editor:app {args} {args}"
96
+ )
97
+ updated = True
98
+ if updated:
99
+ output(":broom: Updating the pyproject.toml")
100
+ with open("pyproject.toml", "w") as out_f:
101
+ tomlkit.dump(pyproject, out_f)
102
+
103
+
104
+ def migrate_ueditor() -> None:
105
+ """Migrate the μEditor to the latest supported version."""
106
+ ueditor_version = "uedition_editor>=2.0.0b5,<2.1"
107
+ output(":hammer: Updating the μEditor")
108
+ with open("pyproject.toml") as in_f:
109
+ pyproject = tomlkit.parse(in_f.read())
110
+ found_ueditor = False
111
+ for idx, dep in enumerate(pyproject["tool"]["hatch"]["envs"]["default"]["dependencies"]):
112
+ dep = dep.lower() # noqa:PLW2901
113
+ if (
114
+ dep == "uedition_editor"
115
+ or dep.startswith("uedition_editor=")
116
+ or dep.startswith("uedition_editor<")
117
+ or dep.startswith("uedition_editor>")
118
+ ):
119
+ pyproject["tool"]["hatch"]["envs"]["default"]["dependencies"][idx] = ueditor_version
120
+ found_ueditor = True
121
+ if not found_ueditor:
122
+ pyproject["tool"]["hatch"]["envs"]["default"]["dependencies"].append(ueditor_version)
123
+ with open("pyproject.toml", "w") as out_f:
124
+ tomlkit.dump(pyproject, out_f)
125
+
126
+
127
+ @app.command()
128
+ def migrate() -> None:
129
+ """Migrate the μEdition to the latest version."""
130
+ if not path.exists("uEdition.yml") and not path.exists("uEdition.yaml") and not path.exists("pyproject.toml"):
131
+ raise NoConfigError()
132
+ output(":hammer: Migrating the μEdition")
133
+ cleanup_old_files()
134
+ cleanup_gitignore()
135
+ cleanup_pyproject()
136
+ migrate_ueditor()
137
+ output(":checkered_flag: Migration complete")
@@ -2,11 +2,13 @@
2
2
  #
3
3
  # SPDX-License-Identifier: MIT
4
4
  """Local server that automatically rebuilds on changes."""
5
+
5
6
  from os import path
6
7
  from typing import Callable
7
8
 
8
9
  from livereload import Server
9
10
 
11
+ from uedition.cli.base import app
10
12
  from uedition.cli.build import full_build, partial_build
11
13
  from uedition.settings import NoConfigError, settings
12
14
 
@@ -27,8 +29,9 @@ def build_cmd(lang: dict, full: bool = True) -> Callable[[], None]: # noqa: FBT
27
29
  return cmd
28
30
 
29
31
 
30
- def run() -> None:
31
- """Run the development server."""
32
+ @app.command()
33
+ def serve() -> None:
34
+ """Run the local μEdition writing server."""
32
35
  if not path.exists("uEdition.yml") and not path.exists("uEdition.yaml"):
33
36
  raise NoConfigError()
34
37
  full_rebuilds = [build_cmd(lang, full=True) for lang in settings["languages"]]
@@ -0,0 +1,84 @@
1
+ # SPDX-FileCopyrightText: 2023-present Mark Hall <mark.hall@work.room3b.eu>
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+ """The μEdition update functionality."""
5
+
6
+ from enum import Enum
7
+ from os import path
8
+
9
+ import httpx
10
+ import tomlkit
11
+ from packaging.specifiers import SpecifierSet
12
+ from packaging.version import Version
13
+ from rich import print as output
14
+
15
+ from uedition.cli.base import app
16
+ from uedition.settings import NoConfigError
17
+
18
+
19
+ class UpdateVersionOptions(Enum):
20
+ """Option settings for upgrade version selection."""
21
+
22
+ RELEASES = "releases"
23
+ PRE_RELEASES = "pre-releases"
24
+
25
+
26
+ @app.command()
27
+ def update(allow_versions: UpdateVersionOptions = UpdateVersionOptions.RELEASES.value) -> None:
28
+ """Update the μEdition to the latest version."""
29
+ try:
30
+ if not path.exists("uEdition.yml") and not path.exists("uEdition.yaml") and not path.exists("pyproject.toml"):
31
+ raise NoConfigError()
32
+ with open("pyproject.toml") as in_f:
33
+ pyproject = tomlkit.parse(in_f.read())
34
+ output(":hourglass_flowing_sand: Determining latest version")
35
+ response = httpx.get(
36
+ "https://pypi.org/simple/uedition/", headers={"Accept": "application/vnd.pypi.simple.v1+json"}
37
+ )
38
+ if response.status_code != 200: # noqa: PLR2004
39
+ output(":cross_mark: Failed to determine the latest version")
40
+ raise Exception("PyPi access error") # noqa: EM101
41
+ versions = response.json()["versions"]
42
+ versions.reverse()
43
+ target_version = None
44
+ for version in versions:
45
+ if Version(version).is_prerelease and allow_versions == UpdateVersionOptions.PRE_RELEASES:
46
+ target_version = Version(version)
47
+ break
48
+ elif not Version(version).is_prerelease:
49
+ target_version = Version(version)
50
+ break
51
+ if target_version is None:
52
+ raise Exception("No version found to upgrade to") # noqa: EM101
53
+ target_specifier = SpecifierSet(f">={target_version},<{target_version.major}.{target_version.minor + 1}")
54
+ output(f":hammer: Upgrading to {target_version}")
55
+ if "tool" not in pyproject:
56
+ pyproject["tool"] = tomlkit.table()
57
+ if "hatch" not in pyproject["tool"]:
58
+ pyproject["tool"]["hatch"] = tomlkit.table()
59
+ if "envs" not in pyproject["tool"]["hatch"]:
60
+ pyproject["tool"]["hatch"]["envs"] = tomlkit.table()
61
+ if "default" not in pyproject["tool"]["hatch"]["envs"]:
62
+ pyproject["tool"]["hatch"]["envs"]["default"] = tomlkit.table()
63
+ if "dependencies" not in pyproject["tool"]["hatch"]["envs"]["default"]:
64
+ pyproject["tool"]["hatch"]["envs"]["default"]["dependencies"] = []
65
+ pyproject["tool"]["hatch"]["envs"]["default"]["skip-install"] = True
66
+ # Upgrade the uEdition version
67
+ found_uedition = False
68
+ for idx, dep in enumerate(pyproject["tool"]["hatch"]["envs"]["default"]["dependencies"]):
69
+ dep = dep.lower() # noqa:PLW2901
70
+ if (
71
+ dep == "uedition"
72
+ or dep.startswith("uedition=")
73
+ or dep.startswith("uedition<")
74
+ or dep.startswith("uedition>")
75
+ ):
76
+ pyproject["tool"]["hatch"]["envs"]["default"]["dependencies"][idx] = f"uedition{target_specifier}"
77
+ found_uedition = True
78
+ if not found_uedition:
79
+ pyproject["tool"]["hatch"]["envs"]["default"]["dependencies"].append(f"uedition{target_specifier}")
80
+ with open("pyproject.toml", "w") as out_f:
81
+ tomlkit.dump(pyproject, out_f)
82
+ output(":checkered_flag: Upgrade complete")
83
+ except Exception as e:
84
+ output(f":cross_mark: Update failed: {e}")
@@ -14,6 +14,8 @@ from sphinx.locale import __
14
14
  from sphinx.util.osutil import ensuredir, os_path
15
15
  from sphinx.writers.xml import XMLWriter
16
16
 
17
+ from uedition.ext.tei.parser import TeiElement
18
+
17
19
  logger = logging.getLogger(__name__)
18
20
 
19
21
  MAPPINGS = [
@@ -37,6 +39,13 @@ MAPPINGS = [
37
39
  },
38
40
  {"cls": nodes.compound, "tagname": "div", "type": "block"},
39
41
  {"cls": nodes.admonition, "tagname": "div", "type": "block"},
42
+ {
43
+ "cls": nodes.definition_list,
44
+ "tagname": "list",
45
+ "type": "block",
46
+ "attrs": [{"target": "type", "value": "definition"}],
47
+ },
48
+ {"cls": nodes.definition_list_item, "tagname": "item", "type": "block"},
40
49
  {"cls": sphinx.addnodes.toctree},
41
50
  {
42
51
  "cls": nodes.footnote,
@@ -105,6 +114,16 @@ class TEITranslator(nodes.GenericNodeVisitor):
105
114
  for rule in MAPPINGS:
106
115
  if isinstance(node, rule["cls"]):
107
116
  return rule
117
+ if isinstance(node, TeiElement):
118
+ tag = node.get("tei_tag")
119
+ tag = tag[tag.find("}") + 1 :]
120
+ attrs = []
121
+ for key, value in node.get("tei_attributes").items():
122
+ if key.startswith("data-tei-block-") or key.startswith("data-tei-mark-"):
123
+ continue
124
+ elif key.startswith("data-tei-attribute-"):
125
+ attrs.append({"target": key[19:], "value": value})
126
+ return {"tagname": tag, "type": "block", "attrs": attrs}
108
127
  self.warn(f"Unknown node {node.__class__.__module__}.{node.__class__.__qualname__} ({node.attlist()})")
109
128
  return {"tagname": "div", "type": "block"}
110
129