shacl2code 0.0.2__tar.gz → 0.0.4__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.
Files changed (30) hide show
  1. {shacl2code-0.0.2 → shacl2code-0.0.4}/.github/workflows/publish.yaml +9 -8
  2. {shacl2code-0.0.2 → shacl2code-0.0.4}/.github/workflows/test.yaml +7 -0
  3. {shacl2code-0.0.2 → shacl2code-0.0.4}/PKG-INFO +32 -1
  4. shacl2code-0.0.4/README.md +32 -0
  5. shacl2code-0.0.4/conftest.py +14 -0
  6. {shacl2code-0.0.2 → shacl2code-0.0.4}/pyproject.toml +12 -1
  7. {shacl2code-0.0.2 → shacl2code-0.0.4/src}/shacl2code/__init__.py +1 -0
  8. shacl2code-0.0.4/src/shacl2code/__main__.py +12 -0
  9. shacl2code-0.0.4/src/shacl2code/lang/__init__.py +10 -0
  10. shacl2code-0.0.4/src/shacl2code/lang/common.py +71 -0
  11. shacl2code-0.0.4/src/shacl2code/lang/lang.py +15 -0
  12. shacl2code-0.0.4/src/shacl2code/lang/python.py +13 -0
  13. shacl2code-0.0.4/src/shacl2code/lang/raw.py +13 -0
  14. shacl2code-0.0.4/src/shacl2code/main.py +93 -0
  15. {shacl2code-0.0.2 → shacl2code-0.0.4/src}/shacl2code/model.py +0 -19
  16. {shacl2code-0.0.2 → shacl2code-0.0.4/src}/shacl2code/templates/python.j2 +1 -0
  17. shacl2code-0.0.4/src/shacl2code/templates/raw.j2 +7 -0
  18. shacl2code-0.0.4/src/shacl2code/version.py +1 -0
  19. shacl2code-0.0.4/tests/data/spdx3-model.jsonld +7816 -0
  20. shacl2code-0.0.4/tests/expect/python/spdx3.py +4039 -0
  21. shacl2code-0.0.4/tests/expect/raw/spdx3.txt +79 -0
  22. shacl2code-0.0.4/tests/test_cli.py +44 -0
  23. shacl2code-0.0.4/tests/test_python.py +107 -0
  24. shacl2code-0.0.4/tests/test_raw.py +117 -0
  25. shacl2code-0.0.2/README.md +0 -4
  26. shacl2code-0.0.2/shacl2code/main.py +0 -69
  27. shacl2code-0.0.2/shacl2code/version.py +0 -1
  28. {shacl2code-0.0.2 → shacl2code-0.0.4}/.gitignore +0 -0
  29. {shacl2code-0.0.2 → shacl2code-0.0.4}/LICENSE +0 -0
  30. {shacl2code-0.0.2 → shacl2code-0.0.4/src}/shacl2code/const.py +0 -0
@@ -1,10 +1,18 @@
1
1
  ---
2
2
  name: Upload Python Package
3
3
  on:
4
- - push
4
+ release:
5
+ types:
6
+ - published
5
7
 
6
8
  jobs:
9
+ test:
10
+ uses: ./.github/workflows/test.yaml
11
+
7
12
  deploy:
13
+ needs:
14
+ - test
15
+
8
16
  runs-on: ubuntu-latest
9
17
  permissions:
10
18
  id-token: write
@@ -25,12 +33,5 @@ jobs:
25
33
  - name: Build package
26
34
  run: python -m build
27
35
 
28
- - name: Publish distribution to Test PyPI
29
- uses: pypa/gh-action-pypi-publish@release/v1
30
- with:
31
- repository-url: https://test.pypi.org/legacy/
32
- skip-existing: true
33
-
34
36
  - name: Publish distribution to PyPI
35
- if: startsWith(github.ref, 'refs/tags')
36
37
  uses: pypa/gh-action-pypi-publish@release/v1
@@ -3,6 +3,7 @@ name: Test shacl2code
3
3
  on:
4
4
  - push
5
5
  - pull_request
6
+ - workflow_call
6
7
 
7
8
  jobs:
8
9
  build:
@@ -28,6 +29,12 @@ jobs:
28
29
  - name: Build package
29
30
  run: |
30
31
  python -m build
32
+ - name: Install package
33
+ run: |
34
+ pip install -e .[dev]
35
+ - name: Run tests
36
+ run: |
37
+ pytest -v
31
38
  lint:
32
39
  runs-on: ubuntu-latest
33
40
  steps:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: shacl2code
3
- Version: 0.0.2
3
+ Version: 0.0.4
4
4
  Summary: Convert SHACL model file to code bindings
5
5
  Project-URL: Homepage, https://github.com/JPEWdev/shacl2code
6
6
  Project-URL: Repository, https://github.com/JPEWdev/shacl2code.git
@@ -19,9 +19,40 @@ Classifier: Programming Language :: Python :: 3.12
19
19
  Classifier: Topic :: Software Development :: Build Tools
20
20
  Requires-Dist: jinja2>=3.1.2
21
21
  Requires-Dist: pyld>=2.0.3
22
+ Provides-Extra: dev
23
+ Requires-Dist: pytest-server-fixtures>=1.7; extra == 'dev'
24
+ Requires-Dist: pytest>=7.4; extra == 'dev'
22
25
  Description-Content-Type: text/markdown
23
26
 
24
27
  # Convert SHACL Model to code bindings
25
28
 
26
29
  This tool can be used to convert a JSONLD SHACL model into various code
27
30
  bindings
31
+
32
+ ## Installation
33
+
34
+ `shacl2code` can be installed using pip:
35
+
36
+ ```shell
37
+ python3 -m pip install shacl2code
38
+ ```
39
+
40
+ ## Usage
41
+
42
+ `shacl2code` can generate bindings from either a local file:
43
+ ```shell
44
+ shacl2code generate -i model.jsonld python -o out.py
45
+ ```
46
+ Or from a URL:
47
+ ```shell
48
+ shacl2code generate -i https://spdx.github.io/spdx-3-model/model.jsonld python -o out.py
49
+ ```
50
+ Or from stdin:
51
+ ```shell
52
+ cat model.jsonld | shacl2code generate -i - python -o - > out.py
53
+ ```
54
+
55
+ For more information, run:
56
+ ```shell
57
+ shacl2code --help
58
+ ```
@@ -0,0 +1,32 @@
1
+ # Convert SHACL Model to code bindings
2
+
3
+ This tool can be used to convert a JSONLD SHACL model into various code
4
+ bindings
5
+
6
+ ## Installation
7
+
8
+ `shacl2code` can be installed using pip:
9
+
10
+ ```shell
11
+ python3 -m pip install shacl2code
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ `shacl2code` can generate bindings from either a local file:
17
+ ```shell
18
+ shacl2code generate -i model.jsonld python -o out.py
19
+ ```
20
+ Or from a URL:
21
+ ```shell
22
+ shacl2code generate -i https://spdx.github.io/spdx-3-model/model.jsonld python -o out.py
23
+ ```
24
+ Or from stdin:
25
+ ```shell
26
+ cat model.jsonld | shacl2code generate -i - python -o - > out.py
27
+ ```
28
+
29
+ For more information, run:
30
+ ```shell
31
+ shacl2code --help
32
+ ```
@@ -0,0 +1,14 @@
1
+ #
2
+ # Copyright (c) 2024 Joshua Watt
3
+ #
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ import pytest
7
+ from pytest_server_fixtures.http import SimpleHTTPTestServer
8
+
9
+
10
+ @pytest.fixture
11
+ def http_server():
12
+ with SimpleHTTPTestServer() as s:
13
+ s.start()
14
+ yield s
@@ -24,6 +24,12 @@ classifiers = [
24
24
  "Programming Language :: Python :: 3.12",
25
25
  ]
26
26
 
27
+ [project.optional-dependencies]
28
+ dev = [
29
+ "pytest >= 7.4",
30
+ "pytest-server-fixtures >= 1.7"
31
+ ]
32
+
27
33
  [project.urls]
28
34
  Homepage = "https://github.com/JPEWdev/shacl2code"
29
35
  Repository = "https://github.com/JPEWdev/shacl2code.git"
@@ -37,4 +43,9 @@ requires = ["hatchling"]
37
43
  build-backend = "hatchling.build"
38
44
 
39
45
  [tool.hatch.version]
40
- path = "shacl2code/version.py"
46
+ path = "src/shacl2code/version.py"
47
+
48
+ [tool.pytest.ini_options]
49
+ addopts = [
50
+ "--import-mode=importlib",
51
+ ]
@@ -1,2 +1,3 @@
1
1
  from .model import Model
2
2
  from .main import main
3
+ from .version import VERSION
@@ -0,0 +1,12 @@
1
+ #! /usr/bin/env python3
2
+ #
3
+ # Copyright (c) 2024 Joshua Watt
4
+ #
5
+ # SPDX-License-Identifier: MIT
6
+
7
+ import sys
8
+
9
+ from . import main
10
+
11
+ if __name__ == "__main__":
12
+ sys.exit(main())
@@ -0,0 +1,10 @@
1
+ #
2
+ # Copyright (c) 2024 Joshua Watt
3
+ #
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ from .lang import LANGUAGES
7
+
8
+ # All renderers must be imported here to be registered
9
+ from .python import PythonRender
10
+ from .raw import RawRender
@@ -0,0 +1,71 @@
1
+ #
2
+ # Copyright (c) 2024 Joshua Watt
3
+ #
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ import sys
7
+ import os
8
+ from contextlib import contextmanager
9
+ from pathlib import Path
10
+ from jinja2 import Environment, FileSystemLoader, TemplateRuntimeError
11
+
12
+ from ..const import TEMPLATE_DIR
13
+
14
+
15
+ class OutputFile(object):
16
+ def __init__(self, path):
17
+ self.path = path
18
+
19
+ @contextmanager
20
+ def open(self):
21
+ if self.path == "-":
22
+ yield sys.stdout
23
+ else:
24
+ with open(self.path, "w") as f:
25
+ yield f
26
+
27
+
28
+ class BasicJinjaRender(object):
29
+ """
30
+ Common Jinja Template Renderer
31
+
32
+ Renderers that only use a single Jinja file can derive from this class. The
33
+ class should set the class member variable `TEMPLATE` to indicate which
34
+ template file to use. For example:
35
+
36
+ @language("my-lang")
37
+ class MyRendered(BasicJinjaRenderer):
38
+ HELP = "Generates my-lang bindings"
39
+ TEMPLATE = "my-lang.j2"
40
+
41
+ """
42
+
43
+ def __init__(self):
44
+ pass
45
+
46
+ @classmethod
47
+ def get_arguments(cls, parser):
48
+ parser.add_argument(
49
+ "--output",
50
+ "-o",
51
+ type=OutputFile,
52
+ help="Output file or '-' for stdout",
53
+ required=True,
54
+ )
55
+
56
+ def output(self, args, model):
57
+ def abort_helper(msg):
58
+ raise TemplateRuntimeError(msg)
59
+
60
+ env = Environment(loader=FileSystemLoader(TEMPLATE_DIR))
61
+ env.globals["abort"] = abort_helper
62
+ template = env.get_template(self.TEMPLATE)
63
+
64
+ render = template.render(
65
+ disclaimer=f"This file was automatically generated by {os.path.basename(sys.argv[0])}. DO NOT MANUALLY MODIFY IT",
66
+ enums=model.get_template_enums(),
67
+ classes=model.get_template_classes(),
68
+ )
69
+
70
+ with args.output.open() as f:
71
+ f.write(render)
@@ -0,0 +1,15 @@
1
+ #
2
+ # Copyright (c) 2024 Joshua Watt
3
+ #
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ LANGUAGES = {}
7
+
8
+
9
+ def language(name):
10
+ def inner(cls):
11
+ global LANGUAGES
12
+ LANGUAGES[name] = cls
13
+ return cls
14
+
15
+ return inner
@@ -0,0 +1,13 @@
1
+ #
2
+ # Copyright (c) 2024 Joshua Watt
3
+ #
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ from .common import BasicJinjaRender
7
+ from .lang import language
8
+
9
+
10
+ @language("python")
11
+ class PythonRender(BasicJinjaRender):
12
+ HELP = "Python Language Bindings"
13
+ TEMPLATE = "python.j2"
@@ -0,0 +1,13 @@
1
+ #
2
+ # Copyright (c) 2024 Joshua Watt
3
+ #
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ from .common import BasicJinjaRender
7
+ from .lang import language
8
+
9
+
10
+ @language("raw")
11
+ class RawRender(BasicJinjaRender):
12
+ HELP = "Raw Jinja Output (for testing)"
13
+ TEMPLATE = "raw.j2"
@@ -0,0 +1,93 @@
1
+ #! /usr/bin/env python3
2
+ #
3
+ # Copyright (c) 2024 Joshua Watt
4
+ #
5
+ # SPDX-License-Identifier: MIT
6
+
7
+ import argparse
8
+ import json
9
+ import sys
10
+ import urllib.request
11
+ from pathlib import Path
12
+
13
+ from . import Model
14
+ from .version import VERSION
15
+ from .lang import LANGUAGES
16
+
17
+
18
+ def main():
19
+ def handle_generate(args):
20
+ if "://" in args.input:
21
+ with urllib.request.urlopen(args.input) as url:
22
+ model_data = json.load(url)
23
+ elif args.input == "-":
24
+ model_data = json.load(sys.stdin)
25
+ else:
26
+ with Path(args.input).open("r") as f:
27
+ model_data = json.load(f)
28
+
29
+ m = Model(model_data)
30
+
31
+ render = args.lang()
32
+ render.output(args, m)
33
+ return 0
34
+
35
+ def handle_list(args):
36
+ width = max(len(lang) for lang in LANGUAGES)
37
+ for k, v in LANGUAGES.items():
38
+ if args.short:
39
+ print(k)
40
+ else:
41
+ print(f"{k:{width}} - {v.HELP}")
42
+
43
+ return 0
44
+
45
+ def handle_version(args):
46
+ print(VERSION)
47
+ return 0
48
+
49
+ parser = argparse.ArgumentParser(
50
+ description=f"Convert JSON-LD model to python. Version {VERSION}"
51
+ )
52
+ command_subparser = parser.add_subparsers(
53
+ title="command",
54
+ description="Command to execute",
55
+ required=True,
56
+ )
57
+ generate_parser = command_subparser.add_parser(
58
+ "generate",
59
+ help="Generate language bindings",
60
+ )
61
+ generate_parser.add_argument(
62
+ "--input",
63
+ "-i",
64
+ help="Input JSON-LD model (path, URL, or '-')",
65
+ required=True,
66
+ )
67
+ generate_parser.set_defaults(func=handle_generate)
68
+
69
+ lang_subparser = generate_parser.add_subparsers(
70
+ title="language",
71
+ description="Language to generate",
72
+ required=True,
73
+ )
74
+ for k, v in LANGUAGES.items():
75
+ p = lang_subparser.add_parser(k, help=v.HELP)
76
+ v.get_arguments(p)
77
+ p.set_defaults(lang=v)
78
+
79
+ list_parser = command_subparser.add_parser("list", help="List languages")
80
+ list_parser.add_argument(
81
+ "--short",
82
+ "-s",
83
+ action="store_true",
84
+ help="Only list languages without descriptions",
85
+ )
86
+ list_parser.set_defaults(func=handle_list)
87
+
88
+ version_parser = command_subparser.add_parser("version", help="Show version")
89
+ version_parser.set_defaults(func=handle_version)
90
+
91
+ args = parser.parse_args()
92
+
93
+ return args.func(args)
@@ -9,11 +9,6 @@ import re
9
9
  from pathlib import Path
10
10
 
11
11
  from pyld import jsonld
12
- from jinja2 import Environment, FileSystemLoader, TemplateRuntimeError
13
-
14
- from .const import TEMPLATE_DIR
15
-
16
- THIS_FILE = Path(__file__)
17
12
 
18
13
 
19
14
  def get_prop(o, name, key, default=None):
@@ -207,17 +202,3 @@ class Model(object):
207
202
  done_classes.add(clsname)
208
203
 
209
204
  return template_classes
210
-
211
- def render_template(self, lang):
212
- def abort_helper(msg):
213
- raise TemplateRuntimeError(msg)
214
-
215
- env = Environment(loader=FileSystemLoader(TEMPLATE_DIR))
216
- env.globals["abort"] = abort_helper
217
- template = env.get_template(lang + ".j2")
218
-
219
- return template.render(
220
- disclaimer=f"This file was automatically generated by {THIS_FILE.name}. DO NOT MANUALLY MODIFY IT",
221
- enums=self.get_template_enums(),
222
- classes=self.get_template_classes(),
223
- )
@@ -858,3 +858,4 @@ if __name__ == "__main__":
858
858
  import sys
859
859
 
860
860
  sys.exit(main())
861
+
@@ -0,0 +1,7 @@
1
+ {% for enum in enums %}
2
+ {{ enum -}}
3
+ {% endfor %}
4
+ {% for class in classes %}
5
+ {{ class -}}
6
+ {% endfor %}
7
+
@@ -0,0 +1 @@
1
+ VERSION = "0.0.4"