uEdition 2.0.0a1__py3-none-any.whl → 2.0.0b1__py3-none-any.whl

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.

uedition/__about__.py CHANGED
@@ -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"
uedition/cli/__init__.py CHANGED
@@ -2,60 +2,17 @@
2
2
  #
3
3
  # SPDX-License-Identifier: MIT
4
4
  """uEdtion Command-line Tool."""
5
- import typer
6
- from rich import print as print_cli
5
+
6
+ from rich import print as output
7
7
 
8
8
  from uedition.__about__ import __version__
9
- from uedition.cli import build as build_module
10
- from uedition.cli import create as create_module
11
- from uedition.cli import language as language_module
12
- from uedition.cli import serve as serve_module
13
- from uedition.cli import update as update_module
9
+ from uedition.cli import build, init, language, migrate, serve, update # noqa:F401
10
+ from uedition.cli.base import app
14
11
  from uedition.settings import settings
15
12
 
16
- app = typer.Typer()
17
- language_app = typer.Typer()
18
- app.add_typer(language_app, name="language")
19
-
20
-
21
- @app.command()
22
- def create(path: str) -> None:
23
- """Create a new μEdition."""
24
- create_module.run(path)
25
-
26
-
27
- @app.command()
28
- def build() -> None:
29
- """Build the μEdition."""
30
- build_module.run()
31
-
32
-
33
- @app.command()
34
- def serve() -> None:
35
- """Serve the μEdition for writing."""
36
- serve_module.run()
37
-
38
-
39
- @app.command()
40
- def update() -> None:
41
- """Update the μEdition."""
42
- update_module.run()
43
-
44
13
 
45
14
  @app.command()
46
15
  def version() -> None:
47
16
  """Output the current μEdition version."""
48
- print_cli(f"μEdition: {__version__}")
49
- print_cli(f'Configuration: {settings["version"]}')
50
-
51
-
52
- @language_app.command("add")
53
- def language_add(path: str) -> None:
54
- """Add a language to the μEdition."""
55
- language_module.add(path)
56
-
57
-
58
- @language_app.command("update")
59
- def language_update(path: str) -> None:
60
- """Update a language."""
61
- language_module.update(path)
17
+ output(f"μEdition: {__version__}")
18
+ output(f"Configuration: {settings['version']}")
uedition/cli/base.py ADDED
@@ -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()
uedition/cli/build.py CHANGED
@@ -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"]):
uedition/cli/init.py ADDED
@@ -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)
uedition/cli/language.py CHANGED
@@ -1,58 +1,63 @@
1
1
  # SPDX-FileCopyrightText: 2023-present Mark Hall <mark.hall@work.room3b.eu>
2
2
  #
3
3
  # SPDX-License-Identifier: MIT
4
- """The μEdition language functionality for managing languages used in the μEdition."""
4
+ """The μEdition language functionality."""
5
+
5
6
  import os
7
+ from typing import Annotated
6
8
 
7
- from copier import run_copy, run_update
8
- from yaml import dump, safe_load
9
+ from rich import print as output
10
+ from typer import Option, Typer
11
+ from yaml import safe_dump, safe_load
9
12
 
13
+ from uedition.cli.base import app
10
14
  from uedition.settings import NoConfigError
11
15
 
12
-
13
- def add(path: str) -> None:
14
- """Add a language to the μEdition using Copier."""
15
- if not os.path.exists("uEdition.yml") and not os.path.exists("uEdition.yaml"):
16
- raise NoConfigError()
17
- run_copy("gh:uEdition/uEdition-language-template", path, data={"path": path})
18
- with open(os.path.join(path, ".uEdition.answers")) as in_f:
19
- answers = safe_load(in_f)
20
- with open("uEdition.yml") as in_f:
21
- config = safe_load(in_f)
22
- found = False
23
- if "languages" in config:
24
- for lang in config["languages"]:
25
- if lang["code"] == answers["code"]:
26
- lang["label"] = answers["label"]
27
- lang["path"] = path
28
- found = True
29
- else:
30
- config["languages"] = []
31
- if not found:
32
- config["languages"].append({"code": answers["code"], "label": answers["label"], "path": path})
33
- with open("uEdition.yml", "w") as out_f:
34
- dump(config, out_f)
16
+ lang_app = Typer(help="Language configuration functionality")
17
+ app.add_typer(lang_app, name="language")
35
18
 
36
19
 
37
- def update(path: str) -> None:
38
- """Update a language to the latest template."""
39
- if not os.path.exists("uEdition.yml") and not os.path.exists("uEdition.yaml"):
40
- raise NoConfigError()
41
- run_update(path, answers_file=".uEdition.answers", overwrite=True, data={"path": path})
42
- with open(os.path.join(path, ".uEdition.answers")) as in_f:
43
- answers = safe_load(in_f)
44
- with open("uEdition.yml") as in_f:
45
- config = safe_load(in_f)
46
- found = False
47
- if "languages" in config:
48
- for lang in config["languages"]:
49
- if lang["code"] == answers["code"]:
50
- lang["label"] = answers["label"]
51
- lang["path"] = path
52
- found = True
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)
53
39
  else:
40
+ raise NoConfigError()
41
+ if "languages" not in config:
54
42
  config["languages"] = []
55
- if not found:
56
- config["languages"].append({"code": answers["code"], "label": answers["label"], "path": path})
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
57
60
  with open("uEdition.yml", "w") as out_f:
58
- dump(config, 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")
uedition/cli/serve.py CHANGED
@@ -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"]]
uedition/cli/update.py CHANGED
@@ -1,16 +1,84 @@
1
1
  # SPDX-FileCopyrightText: 2023-present Mark Hall <mark.hall@work.room3b.eu>
2
2
  #
3
3
  # SPDX-License-Identifier: MIT
4
- """The μEdition check functionality for validating a μEdition and its files."""
4
+ """The μEdition update functionality."""
5
+
6
+ from enum import Enum
5
7
  from os import path
6
8
 
7
- from copier import run_update
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
8
14
 
15
+ from uedition.cli.base import app
9
16
  from uedition.settings import NoConfigError
10
17
 
11
18
 
12
- def run() -> None:
13
- """Update the μEdition using Copier."""
14
- if not path.exists("uEdition.yml") and not path.exists("uEdition.yaml"):
15
- raise NoConfigError()
16
- run_update(".", answers_file=".uEdition.answers", overwrite=True, skip_answered=True)
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
 
@@ -104,10 +104,15 @@ class TEIParser(SphinxParser):
104
104
  source.sort(key=self._sort_key(conf_section["sort"]))
105
105
  doc_section.append(section)
106
106
  for source in sources:
107
- tmp = nodes.section(ids=[source.attrib["id"]])
108
- for child in source:
109
- self._walk_tree(child, tmp)
110
- section.append(tmp)
107
+ tmp = None
108
+ if "id" in source.attrib:
109
+ tmp = nodes.section(ids=[source.attrib["id"]])
110
+ elif "{http://www.w3.org/XML/1998/namespace}id" in source.attrib:
111
+ tmp = nodes.section(ids=[source.attrib["{http://www.w3.org/XML/1998/namespace}id"]])
112
+ if tmp is not None and len(source) > 0:
113
+ for child in source:
114
+ self._walk_tree(child, tmp)
115
+ section.append(tmp)
111
116
  # self._wrap_sections(section, tmp)
112
117
  elif conf_section["type"] == "metadata":
113
118
  # Process a field or metadata section
@@ -169,8 +174,12 @@ class TEIParser(SphinxParser):
169
174
  element = TeiElement(
170
175
  html_tag=conf["tag"] if conf["tag"] else "span", tei_tag=node.tag, tei_attributes=attrs
171
176
  )
172
- if len(node) == 0 and node.text:
173
- element.append(nodes.Text(node.text))
177
+ if len(node) == 0:
178
+ if conf["text"]:
179
+ for match in node.xpath(conf["text"], namespaces=namespaces):
180
+ element.append(nodes.Text(match))
181
+ elif node.text:
182
+ element.append(nodes.Text(node.text))
174
183
  else:
175
184
  for child in node:
176
185
  self._walk_tree(child, element)
@@ -179,7 +188,7 @@ class TEIParser(SphinxParser):
179
188
  if len(node) == 0:
180
189
  parent.append(nodes.Text(node.text))
181
190
  else:
182
- logger.warning(f"No block or mark configured for {node.tag}")
191
+ logger.warning(f"No block or mark configured for {node.tag} ({node.attrib})")
183
192
 
184
193
  def _parse_attributes(self, node: etree.Element, attribute_configs: list) -> dict:
185
194
  attrs = {}
@@ -256,7 +265,7 @@ class TEIParser(SphinxParser):
256
265
 
257
266
  def _parse_list_field(self: "TEIParser", parent: etree.Element, field: dict, root: etree.Element) -> None:
258
267
  """Parse a list of metadata fields."""
259
- content = root.xpath(field["content"], namespaces=namespaces)
268
+ content = root.xpath(field["selector"], namespaces=namespaces)
260
269
  if len(content) > 0:
261
270
  li = nodes.definition_list_item()
262
271
  dt = nodes.term()
@@ -274,7 +283,7 @@ class TEIParser(SphinxParser):
274
283
 
275
284
  def _parse_download_field(self: "TEIParser", parent: etree.Element, field: dict, root: etree.Element) -> None:
276
285
  """Parse a download metadata field."""
277
- content = root.xpath(field["content"], namespaces=namespaces)
286
+ content = root.xpath(field["selector"], namespaces=namespaces)
278
287
  target = root.xpath(field["target"], namespaces=namespaces)
279
288
  if len(content) > 0 and len(target) > 0:
280
289
  if isinstance(content, list):
@@ -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,27 @@
1
+ uedition/__about__.py,sha256=igeteuzPnSden9GXP0P5R-IDvMoaA-z1geZwMH_24Mw,160
2
+ uedition/__init__.py,sha256=xDDK2i5l1NLhxq6_LJH5g7UJDrFEjIJNmT2tcg7xNWI,301
3
+ uedition/__main__.py,sha256=Pg_yGV-ndR2iiImDC3f017llSX6pSYMslIwZlw8vEpQ,189
4
+ uedition/settings.py,sha256=G73r6muJmRzuENZ-2n51bBf88qS3tRv0kdxr2SRt1j4,5048
5
+ uedition/cli/__init__.py,sha256=3UpRbkx28iIvg0A3yLL-hHQS_TBkRzf8eoHW6ICSR8k,562
6
+ uedition/cli/base.py,sha256=wi8hQbNlC5u0xdagd4x9GEV8W8WhVbEk5WoC8cECniw,174
7
+ uedition/cli/build.py,sha256=aVKFLsZ0XZ2cexx4Bc2z75b4vNn207d8_m5W3IsMUfU,8555
8
+ uedition/cli/init.py,sha256=yD4l1ZhSlq_ftdrfv2wa0WPNwDnuP0lQ2WGR757jb7g,730
9
+ uedition/cli/language.py,sha256=EgjphwNH_2all60Tnc2FFMR8ZRV_Ox_hiD_h2r18Sd0,1988
10
+ uedition/cli/migrate.py,sha256=U4Whtat02Baa_fhlUaDcgBl6f8Jvp1GStyONxF5fXsI,5672
11
+ uedition/cli/serve.py,sha256=640qCCalJBXcLtdgep6e0xITaF5oa3_hbUrh--6mMY0,1577
12
+ uedition/cli/update.py,sha256=XRhv9Fdvcf_iKxZMW4Oz1_5h0OSbf32y18gKijFjOQk,3752
13
+ uedition/ext/__init__.py,sha256=hAK3MB5il4tAkfWnZNVxIJhfJ5vN0Fdmmtz0ZAYsvo4,406
14
+ uedition/ext/config.py,sha256=zu0XSH3Ca09n--umhUJ7k6611lVCecOTVZCWAFn4TRU,994
15
+ uedition/ext/language_switcher.css,sha256=y4LzkCgCm6E_nHt15I4Ku5QzBNpjwda9bt9FsqD1ybM,132
16
+ uedition/ext/language_switcher.js,sha256=HIgQiLg0WGS_G_VjpfEpTDLqb1HwHxcL3r6mdoSUix4,2697
17
+ uedition/ext/language_switcher.py,sha256=tHpf4HsvMtatVn5dQ3EFlrk5urFaMzsZZY755cvgCu8,1425
18
+ uedition/ext/settings.py,sha256=CCbvwlWjhikhoeRZ5E_SuA4zUIqDBMkRes_hjOUxjWk,3735
19
+ uedition/ext/tei/__init__.py,sha256=8KgVi31bz8nI65m6u4EdT_f1qNCP45HrU0V7MSGlZxA,1074
20
+ uedition/ext/tei/builder.py,sha256=XcMv_QTGM1zs86lbdQ2Maotl_7RPEvZ004XM9G7orBM,12539
21
+ uedition/ext/tei/parser.py,sha256=b-1jYRd_9994BzVglY_zadFmQkTJHcE2qbp_wa2hnNA,13813
22
+ uedition/ext/tei/tei_download.js,sha256=5_IPCuamZGPXWriPPPz5wA-zo0Y0Oy1858S6ltxSdQ8,2151
23
+ uedition-2.0.0b1.dist-info/METADATA,sha256=PVpjm2v-vfhhy6OtLYd218p7lQXF8yIG8Kgkio7mdAM,2674
24
+ uedition-2.0.0b1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
25
+ uedition-2.0.0b1.dist-info/entry_points.txt,sha256=cDOOVBb1SZ072ZkY1hW4Y7I_WKKGCtCJtDY1XST1Hr4,96
26
+ uedition-2.0.0b1.dist-info/licenses/LICENSE.txt,sha256=MhLJl8GE8mnuO5i_pvKaobpIGnhiAEdkY-a6LKiuwCE,1101
27
+ uedition-2.0.0b1.dist-info/RECORD,,
uedition/cli/create.py DELETED
@@ -1,10 +0,0 @@
1
- # SPDX-FileCopyrightText: 2023-present Mark Hall <mark.hall@work.room3b.eu>
2
- #
3
- # SPDX-License-Identifier: MIT
4
- """The μEdition create functionality for creating a new μEdition from the project template."""
5
- from copier import run_copy
6
-
7
-
8
- def run(path: str) -> None:
9
- """Create a new μEdition using Copier."""
10
- run_copy("gh:uEdition/uEdition-project-template", path)
@@ -1,25 +0,0 @@
1
- uedition/__about__.py,sha256=kq7WGmRyG7G8lDeopl9H4oZ4X9xtex9Qs3BryTuumU0,160
2
- uedition/__init__.py,sha256=xDDK2i5l1NLhxq6_LJH5g7UJDrFEjIJNmT2tcg7xNWI,301
3
- uedition/__main__.py,sha256=Pg_yGV-ndR2iiImDC3f017llSX6pSYMslIwZlw8vEpQ,189
4
- uedition/settings.py,sha256=G73r6muJmRzuENZ-2n51bBf88qS3tRv0kdxr2SRt1j4,5048
5
- uedition/cli/__init__.py,sha256=gnpl_N8uaw-4uF5ByWV3jXveJBvjLb_uay5YkYCUQWw,1478
6
- uedition/cli/build.py,sha256=L_-OsIEFBXQh-aTHLwLhOXJzXqRH61X2SgVIPxmUgQ0,8169
7
- uedition/cli/create.py,sha256=Q-SvDq9VtmUP4DQhuuvt1eZ_72sX8_tcFOj2Bt_T6J8,371
8
- uedition/cli/language.py,sha256=JAyUwNa4gwqMvrJDPPKGkMLm5Cx9sHJkU5r6xTAMb7M,2214
9
- uedition/cli/serve.py,sha256=FcKp0IbjcyCgn1XjU8VdhI59pGRMNCSXa5jbAS23nxs,1513
10
- uedition/cli/update.py,sha256=SmAcczHxj3j3X0QYplvXPoIHS8XEfXYVqgXBney0v9c,550
11
- uedition/ext/__init__.py,sha256=hAK3MB5il4tAkfWnZNVxIJhfJ5vN0Fdmmtz0ZAYsvo4,406
12
- uedition/ext/config.py,sha256=zu0XSH3Ca09n--umhUJ7k6611lVCecOTVZCWAFn4TRU,994
13
- uedition/ext/language_switcher.css,sha256=y4LzkCgCm6E_nHt15I4Ku5QzBNpjwda9bt9FsqD1ybM,132
14
- uedition/ext/language_switcher.js,sha256=HIgQiLg0WGS_G_VjpfEpTDLqb1HwHxcL3r6mdoSUix4,2697
15
- uedition/ext/language_switcher.py,sha256=tHpf4HsvMtatVn5dQ3EFlrk5urFaMzsZZY755cvgCu8,1425
16
- uedition/ext/settings.py,sha256=CCbvwlWjhikhoeRZ5E_SuA4zUIqDBMkRes_hjOUxjWk,3735
17
- uedition/ext/tei/__init__.py,sha256=8KgVi31bz8nI65m6u4EdT_f1qNCP45HrU0V7MSGlZxA,1074
18
- uedition/ext/tei/builder.py,sha256=LkLR3cu1M6lHHdcjhH5esZ9Qn6eFBXCZWkxVxdXv69E,11719
19
- uedition/ext/tei/parser.py,sha256=ebeqEiji2RZ-Gfszf0Yaa-Lqww-EPqLmxXiMBq-gj90,13216
20
- uedition/ext/tei/tei_download.js,sha256=5_IPCuamZGPXWriPPPz5wA-zo0Y0Oy1858S6ltxSdQ8,2151
21
- uedition-2.0.0a1.dist-info/METADATA,sha256=YquOplbaOq4Z17fRpMEQMK2S1imGpd0HS3TWeCaWXEk,2572
22
- uedition-2.0.0a1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
23
- uedition-2.0.0a1.dist-info/entry_points.txt,sha256=cDOOVBb1SZ072ZkY1hW4Y7I_WKKGCtCJtDY1XST1Hr4,96
24
- uedition-2.0.0a1.dist-info/licenses/LICENSE.txt,sha256=MhLJl8GE8mnuO5i_pvKaobpIGnhiAEdkY-a6LKiuwCE,1101
25
- uedition-2.0.0a1.dist-info/RECORD,,