fastsandpm 0.1.0a1__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.
- fastsandpm-0.1.0a1/PKG-INFO +19 -0
- fastsandpm-0.1.0a1/README.md +8 -0
- fastsandpm-0.1.0a1/pyproject.toml +166 -0
- fastsandpm-0.1.0a1/src/fastsandpm/__init__.py +46 -0
- fastsandpm-0.1.0a1/src/fastsandpm/_git_utils.py +175 -0
- fastsandpm-0.1.0a1/src/fastsandpm/_info.py +35 -0
- fastsandpm-0.1.0a1/src/fastsandpm/dependencies.py +362 -0
- fastsandpm-0.1.0a1/src/fastsandpm/manifest.py +247 -0
- fastsandpm-0.1.0a1/src/fastsandpm/py.typed +0 -0
- fastsandpm-0.1.0a1/src/fastsandpm/versioning/__init__.py +69 -0
- fastsandpm-0.1.0a1/src/fastsandpm/versioning/library_version.py +381 -0
- fastsandpm-0.1.0a1/src/fastsandpm/versioning/specifier.py +390 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: fastsandpm
|
|
3
|
+
Version: 0.1.0a1
|
|
4
|
+
Summary: FastSandPM is a a package management and dependency resolution tool for HDL Design and DV projects
|
|
5
|
+
Author: Benjamin Davis
|
|
6
|
+
Author-email: Benjamin Davis <allrisc.dev@gmail.com>
|
|
7
|
+
Requires-Dist: pydantic>=2.12.5
|
|
8
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
9
|
+
Requires-Python: >=3.12
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
# FastSandPM
|
|
13
|
+
A package management and dependency resolution tool for HDL Design and DV projects
|
|
14
|
+
|
|
15
|
+
[](https://github.com/RISCY-Lib/fastsandpm/actions/workflows/run-ci-tests.yml)
|
|
16
|
+
[](https://pypi.org/project/fastsandpm/)
|
|
17
|
+
[](https://fastsandpm.readthedocs.io/en/latest/index.html)
|
|
18
|
+
|
|
19
|
+
See [Read-The-Docs](https://fastsandpm.readthedocs.io/en/latest/index.html) for details
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# FastSandPM
|
|
2
|
+
A package management and dependency resolution tool for HDL Design and DV projects
|
|
3
|
+
|
|
4
|
+
[](https://github.com/RISCY-Lib/fastsandpm/actions/workflows/run-ci-tests.yml)
|
|
5
|
+
[](https://pypi.org/project/fastsandpm/)
|
|
6
|
+
[](https://fastsandpm.readthedocs.io/en/latest/index.html)
|
|
7
|
+
|
|
8
|
+
See [Read-The-Docs](https://fastsandpm.readthedocs.io/en/latest/index.html) for details
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
####################################################################################################
|
|
2
|
+
# FastSandPM is a package management and dependency resolution tool for HDL Design and DV projects
|
|
3
|
+
# Copyright (C) 2026, Benjamin Davis
|
|
4
|
+
#
|
|
5
|
+
# This library is free software; you can redistribute it and/or
|
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
7
|
+
# License as published by the Free Software Foundation; either
|
|
8
|
+
# version 2.1 of the License, or (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# This library is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
13
|
+
# Lesser General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU Lesser General Public
|
|
16
|
+
# License along with this library; if not, see
|
|
17
|
+
# <https://www.gnu.org/licenses/>.
|
|
18
|
+
####################################################################################################
|
|
19
|
+
|
|
20
|
+
[build-system]
|
|
21
|
+
requires = ["uv_build>=0.8.3,<0.9.0"]
|
|
22
|
+
build-backend = "uv_build"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
[project]
|
|
26
|
+
name = "FastSandPM"
|
|
27
|
+
version = "0.1.0a1"
|
|
28
|
+
description = """FastSandPM is a a package management and dependency resolution tool for HDL Design and DV projects"""
|
|
29
|
+
readme = "README.md"
|
|
30
|
+
authors = [
|
|
31
|
+
{ name = "Benjamin Davis", email = "allrisc.dev@gmail.com" }
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
requires-python = ">=3.12"
|
|
35
|
+
dependencies = [
|
|
36
|
+
"pydantic>=2.12.5",
|
|
37
|
+
"pyyaml>=6.0.3",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[dependency-groups]
|
|
41
|
+
dev = [
|
|
42
|
+
"ruff>=0.13.0",
|
|
43
|
+
"tox>=4.25.0",
|
|
44
|
+
"tox-uv>=1.13.1",
|
|
45
|
+
]
|
|
46
|
+
docs=[
|
|
47
|
+
"sphinx>=5.3.0",
|
|
48
|
+
"sphinx-rtd-theme>=2.0.0",
|
|
49
|
+
"sphinx-prompt>=1.10.0",
|
|
50
|
+
"sphinxcontrib-autoprogram>=0.1.9",
|
|
51
|
+
"sphinx-collapse>=0.1.3",
|
|
52
|
+
"myst-parser>=4.0.1",
|
|
53
|
+
]
|
|
54
|
+
tests=[
|
|
55
|
+
"pytest>=7.4.4",
|
|
56
|
+
"pytest-mock>=3.15.1",
|
|
57
|
+
]
|
|
58
|
+
typing=[
|
|
59
|
+
"mypy>=1.4.1",
|
|
60
|
+
"types-pyyaml>=6.0.12.20250516",
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
# Tool Configurations
|
|
64
|
+
####################################################################################################
|
|
65
|
+
[tool.autopep8]
|
|
66
|
+
max-line-length = 100
|
|
67
|
+
|
|
68
|
+
[tool.mypy]
|
|
69
|
+
warn_return_any = true
|
|
70
|
+
pretty = true
|
|
71
|
+
|
|
72
|
+
python_version = "3.12"
|
|
73
|
+
|
|
74
|
+
files = ["src"]
|
|
75
|
+
|
|
76
|
+
[tool.pyright]
|
|
77
|
+
pythonVersion = "3.12"
|
|
78
|
+
include = ["src"]
|
|
79
|
+
typeCheckingMode = "basic"
|
|
80
|
+
|
|
81
|
+
[tool.ruff]
|
|
82
|
+
line-length = 100
|
|
83
|
+
indent-width = 4
|
|
84
|
+
|
|
85
|
+
target-version = "py312"
|
|
86
|
+
show-fixes = true
|
|
87
|
+
|
|
88
|
+
src = ["src"]
|
|
89
|
+
exclude = [".*", "tests/data/*"]
|
|
90
|
+
|
|
91
|
+
[tool.ruff.format]
|
|
92
|
+
quote-style = "double"
|
|
93
|
+
indent-style = "space"
|
|
94
|
+
skip-magic-trailing-comma = false
|
|
95
|
+
line-ending = "auto"
|
|
96
|
+
|
|
97
|
+
[tool.ruff.lint]
|
|
98
|
+
select = [
|
|
99
|
+
"B", # flake8-bugbear
|
|
100
|
+
"N", # pep8-naming
|
|
101
|
+
"E", # pycodestyle error
|
|
102
|
+
"F", # pyflakes
|
|
103
|
+
"I", # isort
|
|
104
|
+
"UP", # pyupgrade
|
|
105
|
+
"W", # pycodestyle warning
|
|
106
|
+
]
|
|
107
|
+
ignore = []
|
|
108
|
+
|
|
109
|
+
preview = true
|
|
110
|
+
|
|
111
|
+
[tool.tox]
|
|
112
|
+
env_list = [
|
|
113
|
+
"py12", "py13", "py14",
|
|
114
|
+
"style",
|
|
115
|
+
"typing",
|
|
116
|
+
"docs_dirhtml",
|
|
117
|
+
]
|
|
118
|
+
|
|
119
|
+
[tool.tox.env_run_base]
|
|
120
|
+
description = "pytest on latest dependency versions"
|
|
121
|
+
runner = "uv-venv-lock-runner"
|
|
122
|
+
package = "wheel"
|
|
123
|
+
wheel_build_env = ".pkg"
|
|
124
|
+
constrain_package_deps = true
|
|
125
|
+
use_frozen_constraints = true
|
|
126
|
+
dependency_groups = ["tests"]
|
|
127
|
+
|
|
128
|
+
commands = [[
|
|
129
|
+
"pytest", "-v", "--tb=short", "--basetemp={env_tmp_dir}",
|
|
130
|
+
{replace = "posargs", default = [], extend = true},
|
|
131
|
+
]]
|
|
132
|
+
|
|
133
|
+
[tool.tox.env.style]
|
|
134
|
+
description = "run linting and style checks on code"
|
|
135
|
+
dependency_groups = ["dev"]
|
|
136
|
+
skip_install = true
|
|
137
|
+
commands = [["ruff", "check"]]
|
|
138
|
+
|
|
139
|
+
[tool.tox.env.typing]
|
|
140
|
+
description = "run static type checkers"
|
|
141
|
+
dependency_groups = ["typing"]
|
|
142
|
+
commands = [
|
|
143
|
+
["mypy"],
|
|
144
|
+
]
|
|
145
|
+
|
|
146
|
+
[tool.tox.env.docs_dirhtml]
|
|
147
|
+
description = "build docs in dirhtml mode"
|
|
148
|
+
dependency_groups = ["docs"]
|
|
149
|
+
allowlist_externals = ["rm"]
|
|
150
|
+
commands_pre = [
|
|
151
|
+
["rm", "-rf", "docs/source/api", "docs/_build/dirhtml",],
|
|
152
|
+
]
|
|
153
|
+
commands = [
|
|
154
|
+
["sphinx-build", "-E", "-W", "-b", "dirhtml", "docs/source", "docs/_build/dirhtml"],
|
|
155
|
+
]
|
|
156
|
+
|
|
157
|
+
[tool.tox.env.docs_html]
|
|
158
|
+
description = "build docs in html mode"
|
|
159
|
+
dependency_groups = ["docs"]
|
|
160
|
+
allowlist_externals = ["rm"]
|
|
161
|
+
commands_pre = [
|
|
162
|
+
["rm", "-rf", "docs/source/api", "docs/_build/html",],
|
|
163
|
+
]
|
|
164
|
+
commands = [
|
|
165
|
+
["sphinx-build", "-E", "-W", "-b", "html", "docs/source", "docs/_build/html"],
|
|
166
|
+
]
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
####################################################################################################
|
|
2
|
+
# FastSandPM is a package management and dependency resolution tool for HDL Design and DV projects
|
|
3
|
+
# Copyright (C) 2026, Benjamin Davis
|
|
4
|
+
#
|
|
5
|
+
# This library is free software; you can redistribute it and/or
|
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
7
|
+
# License as published by the Free Software Foundation; either
|
|
8
|
+
# version 2.1 of the License, or (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# This library is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
13
|
+
# Lesser General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU Lesser General Public
|
|
16
|
+
# License along with this library; if not, see
|
|
17
|
+
# <https://www.gnu.org/licenses/>.
|
|
18
|
+
####################################################################################################
|
|
19
|
+
"""A package management and dependency resolution tool for HDL Design and DV projects
|
|
20
|
+
|
|
21
|
+
This package provides tools for managing RTL and Design Verification projects for HDL projects
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
from fastsandpm import _info
|
|
27
|
+
from fastsandpm.manifest import (
|
|
28
|
+
Manifest,
|
|
29
|
+
ManifestNotFoundError,
|
|
30
|
+
ManifestParseError,
|
|
31
|
+
Package,
|
|
32
|
+
get_manifest,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
__version__ = _info.__version__
|
|
36
|
+
__author__ = _info.__author__
|
|
37
|
+
|
|
38
|
+
__all__ = [
|
|
39
|
+
"__version__",
|
|
40
|
+
"__author__",
|
|
41
|
+
"get_manifest",
|
|
42
|
+
"Manifest",
|
|
43
|
+
"ManifestNotFoundError",
|
|
44
|
+
"ManifestParseError",
|
|
45
|
+
"Package",
|
|
46
|
+
]
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
####################################################################################################
|
|
2
|
+
# FastSandPM is a package management and dependency resolution tool for HDL Design and DV projects
|
|
3
|
+
# Copyright (C) 2026, Benjamin Davis
|
|
4
|
+
#
|
|
5
|
+
# This library is free software; you can redistribute it and/or
|
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
7
|
+
# License as published by the Free Software Foundation; either
|
|
8
|
+
# version 2.1 of the License, or (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# This library is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
13
|
+
# Lesser General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU Lesser General Public
|
|
16
|
+
# License along with this library; if not, see
|
|
17
|
+
# <https://www.gnu.org/licenses/>.
|
|
18
|
+
####################################################################################################
|
|
19
|
+
"""Git utility functions for repository operations.
|
|
20
|
+
|
|
21
|
+
This module provides wrapper functions around git commands for cloning,
|
|
22
|
+
checking out, fetching, and querying git repositories. These utilities
|
|
23
|
+
are used internally by the library controller to manage library dependencies.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
import pathlib
|
|
29
|
+
import subprocess
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def clone(remote: str, dest: pathlib.Path) -> None:
|
|
33
|
+
"""Clone a git repository from a remote URL to a local destination.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
remote: The URL of the remote repository to clone.
|
|
37
|
+
dest: The local path where the repository will be cloned.
|
|
38
|
+
|
|
39
|
+
Raises:
|
|
40
|
+
subprocess.CalledProcessError: If the git clone command fails.
|
|
41
|
+
"""
|
|
42
|
+
subprocess.check_output(["git", "clone", remote, dest], stderr=subprocess.STDOUT)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def checkout(commitish: str, repo: pathlib.Path) -> None:
|
|
46
|
+
"""Checkout a specific commit, branch, or tag in a repository.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
commitish: The commit SHA, branch name, or tag to checkout.
|
|
50
|
+
repo: The path to the local git repository.
|
|
51
|
+
|
|
52
|
+
Raises:
|
|
53
|
+
subprocess.CalledProcessError: If the git checkout command fails.
|
|
54
|
+
"""
|
|
55
|
+
subprocess.check_output(["git", "checkout", commitish], cwd=repo, stderr=subprocess.STDOUT)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def fetch(repo: pathlib.Path) -> None:
|
|
59
|
+
"""Fetch updates from the remote repository.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
repo: The path to the local git repository.
|
|
63
|
+
|
|
64
|
+
Raises:
|
|
65
|
+
subprocess.CalledProcessError: If the git fetch command fails.
|
|
66
|
+
"""
|
|
67
|
+
subprocess.check_output(["git", "fetch"], cwd=repo, stderr=subprocess.STDOUT)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def is_dirty(repo: pathlib.Path) -> bool:
|
|
71
|
+
"""Check if a repository has uncommitted changes.
|
|
72
|
+
|
|
73
|
+
This checks both staged changes (diff-index) and unstaged changes
|
|
74
|
+
(diff-files) to determine if the working directory is dirty.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
repo: The path to the local git repository.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
True if the repository has uncommitted changes, False otherwise.
|
|
81
|
+
"""
|
|
82
|
+
proc = subprocess.run(
|
|
83
|
+
["git", "diff-index", "--quiet", "HEAD", "--"],
|
|
84
|
+
cwd=repo,
|
|
85
|
+
stdout=subprocess.DEVNULL,
|
|
86
|
+
stderr=subprocess.DEVNULL,
|
|
87
|
+
)
|
|
88
|
+
if proc.returncode != 0:
|
|
89
|
+
return True
|
|
90
|
+
|
|
91
|
+
proc = subprocess.run(
|
|
92
|
+
["git", "diff-files", "--quiet"], cwd=repo, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
if proc.returncode != 0 or len(proc.stdout) != 0:
|
|
96
|
+
return True
|
|
97
|
+
|
|
98
|
+
return False
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def remote_exists(remote: str) -> bool:
|
|
102
|
+
"""Check if a remote repository URL is accessible.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
remote: The URL of the remote repository to check.
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
True if the remote repository exists and is accessible, False otherwise.
|
|
109
|
+
"""
|
|
110
|
+
proc = subprocess.run(
|
|
111
|
+
["git", "ls-remote", remote], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
|
|
112
|
+
)
|
|
113
|
+
return proc.returncode == 0
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def get_available_tags(remote: str) -> list[str]:
|
|
117
|
+
"""Get all available tags from a repository.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
remote: The URL of the remote repository.
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
List of tag names from the repository.
|
|
124
|
+
|
|
125
|
+
Raises:
|
|
126
|
+
ValueError: If the remote repository cannot be found.
|
|
127
|
+
"""
|
|
128
|
+
proc = subprocess.run(
|
|
129
|
+
["git", "ls-remote", "--tags", remote],
|
|
130
|
+
stderr=subprocess.STDOUT,
|
|
131
|
+
stdout=subprocess.PIPE,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
if proc.returncode != 0:
|
|
135
|
+
raise ValueError(f"Could not access remote {remote}")
|
|
136
|
+
|
|
137
|
+
tags = []
|
|
138
|
+
for line in proc.stdout.decode("utf-8").split("\n"):
|
|
139
|
+
if line.strip():
|
|
140
|
+
# Parse lines like: "abc123 refs/tags/v1.2.3"
|
|
141
|
+
parts = line.split("\t")
|
|
142
|
+
if len(parts) == 2:
|
|
143
|
+
ref = parts[1]
|
|
144
|
+
if ref.startswith("refs/tags/"):
|
|
145
|
+
tag_name = ref[10:] # Remove 'refs/tags/' prefix
|
|
146
|
+
# Skip tags that end with ^{} (annotated tag references)
|
|
147
|
+
if not tag_name.endswith("^{}"):
|
|
148
|
+
tags.append(tag_name)
|
|
149
|
+
return tags
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def get_remote_file(remote: str, treeish: str, path: str) -> bytes:
|
|
153
|
+
"""Get a file from a remote repository.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
remote: The remote repository URL.
|
|
157
|
+
treeish: The commit, branch, or tag get the file from.
|
|
158
|
+
path: The path of the file in the repository.
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
The contents of the file.
|
|
162
|
+
|
|
163
|
+
Raises:
|
|
164
|
+
ValueError: If the file cannot be fetched from the remote repository.
|
|
165
|
+
"""
|
|
166
|
+
proc = subprocess.run(
|
|
167
|
+
f"git archive --remote={remote} {treeish} {path} | tar xO",
|
|
168
|
+
stderr=subprocess.STDOUT,
|
|
169
|
+
stdout=subprocess.PIPE,
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
if proc.returncode != 0:
|
|
173
|
+
raise ValueError(f"Could not fetch file {path} from remote {remote}")
|
|
174
|
+
|
|
175
|
+
return proc.stdout
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
####################################################################################################
|
|
2
|
+
# FastSandPM is a package management and dependency resolution tool for HDL Design and DV projects
|
|
3
|
+
# Copyright (C) 2026, Benjamin Davis
|
|
4
|
+
#
|
|
5
|
+
# This library is free software; you can redistribute it and/or
|
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
7
|
+
# License as published by the Free Software Foundation; either
|
|
8
|
+
# version 2.1 of the License, or (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# This library is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
13
|
+
# Lesser General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU Lesser General Public
|
|
16
|
+
# License along with this library; if not, see
|
|
17
|
+
# <https://www.gnu.org/licenses/>.
|
|
18
|
+
####################################################################################################
|
|
19
|
+
"""Package metadata for FastSandPM.
|
|
20
|
+
|
|
21
|
+
This module provides package-level metadata including version and author
|
|
22
|
+
information. The version is dynamically retrieved from the installed
|
|
23
|
+
package metadata.
|
|
24
|
+
|
|
25
|
+
Attributes:
|
|
26
|
+
__version__: The current version of the package.
|
|
27
|
+
__author__: The primary author of the package.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
from __future__ import annotations
|
|
31
|
+
|
|
32
|
+
import importlib.metadata
|
|
33
|
+
|
|
34
|
+
__version__: str = importlib.metadata.version("fastsandpm")
|
|
35
|
+
__author__: str = "Benjamin Davis"
|