senfd 0.2.2__tar.gz → 0.3.0__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.
- {senfd-0.2.2/src/senfd.egg-info → senfd-0.3.0}/PKG-INFO +11 -6
- {senfd-0.2.2 → senfd-0.3.0}/README.rst +2 -2
- {senfd-0.2.2 → senfd-0.3.0}/pyproject.toml +15 -9
- senfd-0.3.0/src/senfd/__init__.py +1 -0
- {senfd-0.2.2 → senfd-0.3.0}/src/senfd/cli.py +53 -8
- {senfd-0.2.2 → senfd-0.3.0}/src/senfd/documents/base.py +28 -26
- senfd-0.3.0/src/senfd/documents/enriched.py +1170 -0
- senfd-0.3.0/src/senfd/documents/merged.py +36 -0
- senfd-0.3.0/src/senfd/documents/model.py +98 -0
- {senfd-0.2.2 → senfd-0.3.0}/src/senfd/documents/plain.py +32 -18
- senfd-0.3.0/src/senfd/errors.py +87 -0
- senfd-0.3.0/src/senfd/models.py +94 -0
- senfd-0.3.0/src/senfd/pipeline.py +30 -0
- senfd-0.3.0/src/senfd/schemas/enriched.figure.document.schema.json +3238 -0
- {senfd-0.2.2 → senfd-0.3.0}/src/senfd/schemas/plain.figure.document.schema.json +6 -2
- senfd-0.3.0/src/senfd/skiplist.py +143 -0
- senfd-0.3.0/src/senfd/tables.py +36 -0
- senfd-0.3.0/src/senfd/templates/enriched.figure.document.html.jinja2 +183 -0
- senfd-0.2.2/src/senfd/templates/enriched.figure.document.html.jinja2 → senfd-0.3.0/src/senfd/templates/plain.figure.document.html.jinja2 +1 -4
- {senfd-0.2.2 → senfd-0.3.0/src/senfd.egg-info}/PKG-INFO +11 -6
- {senfd-0.2.2 → senfd-0.3.0}/src/senfd.egg-info/SOURCES.txt +10 -1
- {senfd-0.2.2 → senfd-0.3.0}/src/senfd.egg-info/requires.txt +7 -1
- {senfd-0.2.2 → senfd-0.3.0}/tests/test_case_conversion.py +0 -1
- senfd-0.3.0/tests/test_cli.py +73 -0
- senfd-0.3.0/tests/test_enrichments.py +104 -0
- senfd-0.3.0/tests/test_module.py +28 -0
- senfd-0.3.0/tests/test_release.py +55 -0
- senfd-0.3.0/tests/test_skiplist.py +41 -0
- senfd-0.3.0/tests/test_to_file.py +55 -0
- senfd-0.2.2/src/senfd/__init__.py +0 -1
- senfd-0.2.2/src/senfd/documents/enriched.py +0 -248
- senfd-0.2.2/src/senfd/errors.py +0 -28
- senfd-0.2.2/src/senfd/pipeline.py +0 -27
- senfd-0.2.2/src/senfd/schemas/enriched.figure.document.schema.json +0 -1047
- senfd-0.2.2/src/senfd/tables.py +0 -77
- senfd-0.2.2/tests/test_cli.py +0 -39
- senfd-0.2.2/tests/test_module.py +0 -15
- {senfd-0.2.2 → senfd-0.3.0}/LICENSE +0 -0
- {senfd-0.2.2 → senfd-0.3.0}/setup.cfg +0 -0
- {senfd-0.2.2 → senfd-0.3.0}/src/senfd/documents/__init__.py +0 -0
- {senfd-0.2.2 → senfd-0.3.0}/src/senfd/schemas/__init__.py +0 -0
- {senfd-0.2.2 → senfd-0.3.0}/src/senfd/templates/__init__.py +0 -0
- /senfd-0.2.2/src/senfd/templates/plain.figure.document.html.jinja2 → /senfd-0.3.0/src/senfd/templates/model.document.html.jinja2 +0 -0
- {senfd-0.2.2 → senfd-0.3.0}/src/senfd/utils.py +0 -0
- {senfd-0.2.2 → senfd-0.3.0}/src/senfd.egg-info/dependency_links.txt +0 -0
- {senfd-0.2.2 → senfd-0.3.0}/src/senfd.egg-info/entry_points.txt +0 -0
- {senfd-0.2.2 → senfd-0.3.0}/src/senfd.egg-info/top_level.txt +0 -0
- {senfd-0.2.2 → senfd-0.3.0}/tests/test_schema.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: senfd
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Semantic Enhancer for Figure Documents
|
|
5
5
|
Author-email: "Simon A. F. Lund" <os@safl.dk>
|
|
6
6
|
License: LGPL-2.1-only
|
|
@@ -8,12 +8,17 @@ Description-Content-Type: text/x-rst
|
|
|
8
8
|
License-File: LICENSE
|
|
9
9
|
Requires-Dist: jinja2
|
|
10
10
|
Requires-Dist: pydantic
|
|
11
|
-
Requires-Dist: pytest
|
|
12
|
-
Requires-Dist: pytest-cov
|
|
13
11
|
Requires-Dist: python-docx
|
|
12
|
+
Requires-Dist: tomli
|
|
13
|
+
Provides-Extra: dev
|
|
14
|
+
Requires-Dist: pytest; extra == "dev"
|
|
15
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
16
|
+
Provides-Extra: all
|
|
17
|
+
Requires-Dist: senfd[dev]; extra == "all"
|
|
18
|
+
Dynamic: license-file
|
|
14
19
|
|
|
15
|
-
senfd: Semantic Enricher for
|
|
16
|
-
|
|
20
|
+
senfd: Semantic Enricher for Non-mentioned-Trademark Figure Documents
|
|
21
|
+
=====================================================================
|
|
17
22
|
|
|
18
23
|
.. image:: https://img.shields.io/badge/docs-GitHub%20Pages-blue
|
|
19
24
|
:target: https://safl.github.io/senfd/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
senfd: Semantic Enricher for
|
|
2
|
-
|
|
1
|
+
senfd: Semantic Enricher for Non-mentioned-Trademark Figure Documents
|
|
2
|
+
=====================================================================
|
|
3
3
|
|
|
4
4
|
.. image:: https://img.shields.io/badge/docs-GitHub%20Pages-blue
|
|
5
5
|
:target: https://safl.github.io/senfd/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "senfd"
|
|
3
|
-
|
|
3
|
+
dynamic = ["version"]
|
|
4
4
|
description = "Semantic Enhancer for Figure Documents"
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "Simon A. F. Lund", email = "os@safl.dk" }
|
|
@@ -9,12 +9,18 @@ license = { text = "LGPL-2.1-only" }
|
|
|
9
9
|
dependencies = [
|
|
10
10
|
"jinja2",
|
|
11
11
|
"pydantic",
|
|
12
|
-
"pytest",
|
|
13
|
-
"pytest-cov",
|
|
14
12
|
"python-docx",
|
|
13
|
+
"tomli"
|
|
15
14
|
]
|
|
16
15
|
readme = { file = "README.rst", content-type = "text/x-rst" }
|
|
17
16
|
|
|
17
|
+
[project.optional-dependencies]
|
|
18
|
+
dev = [
|
|
19
|
+
"pytest",
|
|
20
|
+
"pytest-cov",
|
|
21
|
+
]
|
|
22
|
+
all = ["senfd[dev]"]
|
|
23
|
+
|
|
18
24
|
[project.scripts]
|
|
19
25
|
senfd = "senfd.cli:main"
|
|
20
26
|
|
|
@@ -22,20 +28,20 @@ senfd = "senfd.cli:main"
|
|
|
22
28
|
requires = ["setuptools>=42", "wheel"]
|
|
23
29
|
build-backend = "setuptools.build_meta"
|
|
24
30
|
|
|
31
|
+
[tool.setuptools.dynamic]
|
|
32
|
+
version = { attr = "senfd.__version__" }
|
|
33
|
+
|
|
25
34
|
[tool.setuptools.packages.find]
|
|
26
35
|
where = ["src"]
|
|
27
36
|
|
|
28
37
|
[tool.setuptools.package-data]
|
|
29
38
|
"*" = ["*.jinja2", "*.schema.json"]
|
|
30
39
|
|
|
31
|
-
[tool.black]
|
|
32
|
-
line-length = 88
|
|
33
|
-
|
|
34
|
-
[tool.isort]
|
|
35
|
-
profile = "black"
|
|
36
|
-
|
|
37
40
|
[tool.pytest.ini_options]
|
|
38
41
|
addopts = "--maxfail=1 --disable-warnings"
|
|
39
42
|
testpaths = [
|
|
40
43
|
"tests",
|
|
41
44
|
]
|
|
45
|
+
|
|
46
|
+
[tool.ruff]
|
|
47
|
+
line-length = 88
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.3.0"
|
|
@@ -6,22 +6,48 @@ Produces organized and semantically enriched ``.json`` documents from
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import json
|
|
9
|
-
from argparse import ArgumentParser, Namespace
|
|
9
|
+
from argparse import ArgumentParser, Namespace, RawTextHelpFormatter
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
from typing import List
|
|
12
12
|
|
|
13
13
|
import senfd
|
|
14
|
-
import senfd.errors
|
|
15
14
|
import senfd.pipeline
|
|
16
15
|
import senfd.schemas
|
|
17
16
|
from senfd.documents import get_document_classes
|
|
18
17
|
from senfd.documents.base import to_file
|
|
18
|
+
from senfd.documents.merged import FromFolder
|
|
19
|
+
from senfd.errors import Error
|
|
19
20
|
|
|
21
|
+
PARSEARGS_EPILOG = """\
|
|
22
|
+
Senfd
|
|
23
|
+
=====
|
|
20
24
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
) -> Path:
|
|
25
|
+
The --skip-figures flag specifies a path to a TOML file containing a list of
|
|
26
|
+
figures to be skipped during processing.
|
|
24
27
|
|
|
28
|
+
The TOML file must follow this format:
|
|
29
|
+
|
|
30
|
+
[[skip]]
|
|
31
|
+
regex = "^Decimal.and.Binary.Units$"
|
|
32
|
+
matches = 1
|
|
33
|
+
description = ""
|
|
34
|
+
|
|
35
|
+
[[skip]]
|
|
36
|
+
regex = "^Byte, Word, and Dword Relationships$"
|
|
37
|
+
matches = 1
|
|
38
|
+
description = ""
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
Each entry under [[skip]] consists of:
|
|
42
|
+
- regex: A regular expression matching the figure description.
|
|
43
|
+
- matches: The expected number of occurrences of this figure in the document.
|
|
44
|
+
- description: An optional text field describing the reason for skipping.
|
|
45
|
+
|
|
46
|
+
This allows flexible and pattern-based skipping of figures during execution.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def to_log_file(errors: List[Error], filename: str, output: Path) -> Path:
|
|
25
51
|
content = json.dumps(
|
|
26
52
|
[{"type": type(error).__name__, **error.model_dump()} for error in errors],
|
|
27
53
|
indent=4,
|
|
@@ -33,7 +59,11 @@ def to_log_file(
|
|
|
33
59
|
def parse_args() -> Namespace:
|
|
34
60
|
"""Return command-line arguments"""
|
|
35
61
|
|
|
36
|
-
parser = ArgumentParser(
|
|
62
|
+
parser = ArgumentParser(
|
|
63
|
+
description="Semantically organize and enrich figures",
|
|
64
|
+
epilog=PARSEARGS_EPILOG,
|
|
65
|
+
formatter_class=RawTextHelpFormatter,
|
|
66
|
+
)
|
|
37
67
|
parser.add_argument(
|
|
38
68
|
"document", nargs="*", type=Path, help="path to one or more document(s)"
|
|
39
69
|
)
|
|
@@ -48,6 +78,11 @@ def parse_args() -> Namespace:
|
|
|
48
78
|
action="store_true",
|
|
49
79
|
help="dump schema(s) and exit",
|
|
50
80
|
)
|
|
81
|
+
parser.add_argument(
|
|
82
|
+
"--skip-figures",
|
|
83
|
+
type=Path,
|
|
84
|
+
help="Path to toml file that contains list of figure classifiers to skip",
|
|
85
|
+
)
|
|
51
86
|
parser.add_argument(
|
|
52
87
|
"--version",
|
|
53
88
|
action="store_true",
|
|
@@ -75,8 +110,18 @@ def main() -> int:
|
|
|
75
110
|
docclass.to_schema_file(args.output)
|
|
76
111
|
return 0
|
|
77
112
|
|
|
78
|
-
for path in args.document:
|
|
79
|
-
|
|
113
|
+
for count, path in enumerate(sorted(args.document), 1):
|
|
114
|
+
args.output.mkdir(parents=True, exist_ok=True)
|
|
115
|
+
|
|
116
|
+
errors = senfd.pipeline.process(path, args.output, args)
|
|
80
117
|
to_log_file(errors, path.stem, args.output)
|
|
81
118
|
|
|
119
|
+
if FromFolder.is_applicable(args.output): # Merge ModelDocuments
|
|
120
|
+
merged, errors = FromFolder.convert(args.output, args)
|
|
121
|
+
merged.to_json_file(args.output / merged.json_filename())
|
|
122
|
+
|
|
82
123
|
return 0
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
if __name__ == "__main__":
|
|
127
|
+
main()
|
|
@@ -2,23 +2,24 @@
|
|
|
2
2
|
Documents
|
|
3
3
|
=========
|
|
4
4
|
|
|
5
|
-
The following classes model documents at different stages of parsing / processing
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
The following classes model documents at different stages of parsing / processing a
|
|
6
|
+
specification document from a raw extract into something semantically rich.
|
|
8
7
|
"""
|
|
9
8
|
|
|
10
9
|
import importlib.resources as pkg_resources
|
|
11
10
|
import json
|
|
12
11
|
from abc import ABC, abstractmethod
|
|
12
|
+
from argparse import Namespace
|
|
13
13
|
from pathlib import Path
|
|
14
14
|
from typing import Any, ClassVar, Dict, List, Optional, Tuple
|
|
15
15
|
|
|
16
16
|
from jinja2 import Environment, PackageLoader, select_autoescape
|
|
17
|
-
from pydantic import BaseModel, Field
|
|
17
|
+
from pydantic import BaseModel, Field
|
|
18
18
|
|
|
19
19
|
import senfd.schemas
|
|
20
20
|
import senfd.tables
|
|
21
|
-
|
|
21
|
+
import senfd.utils
|
|
22
|
+
from senfd.errors import Error
|
|
22
23
|
|
|
23
24
|
TRANSLATION_TABLE: Dict[int, str] = str.maketrans(
|
|
24
25
|
{
|
|
@@ -63,7 +64,7 @@ def to_file(content: str, filename: str, path: Optional[Path] = None):
|
|
|
63
64
|
if path.is_dir():
|
|
64
65
|
path = path / filename
|
|
65
66
|
|
|
66
|
-
path.write_text(content)
|
|
67
|
+
path.write_text(content, encoding="utf-8")
|
|
67
68
|
|
|
68
69
|
return path
|
|
69
70
|
|
|
@@ -104,7 +105,7 @@ class Document(BaseModel):
|
|
|
104
105
|
"""Writes the document JSON schema to file at the given 'path'"""
|
|
105
106
|
|
|
106
107
|
return to_file(
|
|
107
|
-
json.dumps(cls.
|
|
108
|
+
json.dumps(cls.model_json_schema(), indent=4),
|
|
108
109
|
cls.schema_filename(),
|
|
109
110
|
path,
|
|
110
111
|
)
|
|
@@ -122,7 +123,7 @@ class Document(BaseModel):
|
|
|
122
123
|
def to_json(self) -> str:
|
|
123
124
|
"""Returns the document as a JSON-formatted string"""
|
|
124
125
|
|
|
125
|
-
return self.model_dump_json(
|
|
126
|
+
return self.model_dump_json()
|
|
126
127
|
|
|
127
128
|
def to_json_file(self, path: Optional[Path] = None) -> Path:
|
|
128
129
|
"""Writes the document, formatted as JSON, to file at the given 'path'"""
|
|
@@ -132,42 +133,43 @@ class Document(BaseModel):
|
|
|
132
133
|
def html_filename(self) -> str:
|
|
133
134
|
return f"{self.meta.stem}{self.SUFFIX_HTML}"
|
|
134
135
|
|
|
135
|
-
def to_html(self) -> str:
|
|
136
|
+
def to_html(self, errors: List[Error] = []) -> str:
|
|
136
137
|
"""Returns the document as a HTML-formatted string"""
|
|
137
138
|
|
|
138
139
|
env = Environment(
|
|
139
140
|
loader=PackageLoader("senfd", "templates"),
|
|
140
141
|
autoescape=select_autoescape(["html", "xml"]),
|
|
141
142
|
)
|
|
143
|
+
env.filters["snake_to_pascal"] = senfd.utils.snake_to_pascal
|
|
144
|
+
env.filters["pascal_to_snake"] = senfd.utils.pascal_to_snake
|
|
142
145
|
template = env.get_template(self.FILENAME_HTML_TEMPLATE)
|
|
143
146
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
147
|
+
figure_errors: Dict[int, List[Error]] = {}
|
|
148
|
+
for error in errors:
|
|
149
|
+
if not hasattr(error, "figure_nr"):
|
|
150
|
+
continue
|
|
148
151
|
|
|
149
|
-
|
|
152
|
+
if error.figure_nr not in figure_errors:
|
|
153
|
+
figure_errors[error.figure_nr] = []
|
|
154
|
+
figure_errors[error.figure_nr].append(error)
|
|
150
155
|
|
|
151
|
-
|
|
152
|
-
"""Returns True when validator raises no exceptions, False otherwise"""
|
|
156
|
+
return template.render(document=self.model_dump(), figure_errors=figure_errors)
|
|
153
157
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
return False
|
|
158
|
+
def to_html_file(
|
|
159
|
+
self, path: Optional[Path] = None, errors: List[Error] = []
|
|
160
|
+
) -> Path:
|
|
161
|
+
"""Writes the document to HTML-formatted file"""
|
|
159
162
|
|
|
160
|
-
return
|
|
163
|
+
return to_file(self.to_html(errors), self.html_filename(), path)
|
|
161
164
|
|
|
162
165
|
|
|
163
166
|
class Converter(ABC):
|
|
164
|
-
|
|
165
167
|
@staticmethod
|
|
166
168
|
@abstractmethod
|
|
167
169
|
def is_applicable(path: Path) -> bool:
|
|
168
|
-
|
|
170
|
+
"""Check whether the converter is applicable to the given 'path'"""
|
|
169
171
|
|
|
170
172
|
@staticmethod
|
|
171
173
|
@abstractmethod
|
|
172
|
-
def convert(path: Path) -> Tuple[Document, List[
|
|
173
|
-
|
|
174
|
+
def convert(path: Path, args: Namespace) -> Tuple[Document, List[Error]]:
|
|
175
|
+
"""Convert the given 'path' into a 'Document'"""
|