vcti-path-format-attributes 1.1.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.
- vcti_path_format_attributes-1.1.0/LICENSE +8 -0
- vcti_path_format_attributes-1.1.0/PKG-INFO +142 -0
- vcti_path_format_attributes-1.1.0/README.md +126 -0
- vcti_path_format_attributes-1.1.0/pyproject.toml +40 -0
- vcti_path_format_attributes-1.1.0/setup.cfg +4 -0
- vcti_path_format_attributes-1.1.0/src/vcti/pathformat/attribute/__init__.py +22 -0
- vcti_path_format_attributes-1.1.0/src/vcti/pathformat/attribute/analysis_type.py +14 -0
- vcti_path_format_attributes-1.1.0/src/vcti/pathformat/attribute/file_contents.py +16 -0
- vcti_path_format_attributes-1.1.0/src/vcti/pathformat/attribute/file_structure.py +15 -0
- vcti_path_format_attributes-1.1.0/src/vcti/pathformat/attribute/names.py +17 -0
- vcti_path_format_attributes-1.1.0/src/vcti/pathformat/attribute/path_type.py +12 -0
- vcti_path_format_attributes-1.1.0/src/vcti/pathformat/attribute/py.typed +0 -0
- vcti_path_format_attributes-1.1.0/src/vcti_path_format_attributes.egg-info/PKG-INFO +142 -0
- vcti_path_format_attributes-1.1.0/src/vcti_path_format_attributes.egg-info/SOURCES.txt +18 -0
- vcti_path_format_attributes-1.1.0/src/vcti_path_format_attributes.egg-info/dependency_links.txt +1 -0
- vcti_path_format_attributes-1.1.0/src/vcti_path_format_attributes.egg-info/requires.txt +8 -0
- vcti_path_format_attributes-1.1.0/src/vcti_path_format_attributes.egg-info/top_level.txt +1 -0
- vcti_path_format_attributes-1.1.0/src/vcti_path_format_attributes.egg-info/zip-safe +1 -0
- vcti_path_format_attributes-1.1.0/tests/test_attributes.py +266 -0
- vcti_path_format_attributes-1.1.0/tests/test_version.py +15 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Copyright (c) 2018-2026 Visual Collaboration Technologies Inc.
|
|
2
|
+
All Rights Reserved.
|
|
3
|
+
|
|
4
|
+
This software is proprietary and confidential. Unauthorized copying,
|
|
5
|
+
distribution, or use of this software, via any medium, is strictly
|
|
6
|
+
prohibited. Access is granted only to authorized VCollab developers
|
|
7
|
+
and individuals explicitly authorized by Visual Collaboration
|
|
8
|
+
Technologies Inc.
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vcti-path-format-attributes
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Domain vocabulary enums for file format classification — path types, structures, content, and analysis categories
|
|
5
|
+
Author: Visual Collaboration Technologies Inc.
|
|
6
|
+
Requires-Python: <3.15,>=3.12
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: vcti-enum>=1.0.3
|
|
10
|
+
Provides-Extra: test
|
|
11
|
+
Requires-Dist: pytest; extra == "test"
|
|
12
|
+
Requires-Dist: pytest-cov; extra == "test"
|
|
13
|
+
Provides-Extra: lint
|
|
14
|
+
Requires-Dist: ruff; extra == "lint"
|
|
15
|
+
Dynamic: license-file
|
|
16
|
+
|
|
17
|
+
# Path Format Attributes
|
|
18
|
+
|
|
19
|
+
Domain vocabulary enums for file format classification — path types, structures, content, and analysis categories.
|
|
20
|
+
|
|
21
|
+
Part of the path-format ecosystem:
|
|
22
|
+
**attributes** (this package) · **vcti-python-path-format** (framework) · **vcti-python-path-format-descriptors** (format plugins)
|
|
23
|
+
|
|
24
|
+
This package is the shared taxonomy — it defines the classification
|
|
25
|
+
dimensions that format descriptors and identification rules use. It lives
|
|
26
|
+
in its own repository so that vocabulary changes are deliberate and
|
|
27
|
+
reviewed across all formats. See [docs/ecosystem.md](docs/ecosystem.md)
|
|
28
|
+
for how the three repos work together, and
|
|
29
|
+
[docs/extending.md](docs/extending.md) for how to add new members and
|
|
30
|
+
enums.
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install vcti-path-format-attributes>=1.1.0
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### In `pyproject.toml` dependencies
|
|
39
|
+
|
|
40
|
+
```toml
|
|
41
|
+
dependencies = [
|
|
42
|
+
"vcti-path-format-attributes>=1.1.0",
|
|
43
|
+
]
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Quick Start
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from vcti.pathformat.attribute import (
|
|
52
|
+
AnalysisType,
|
|
53
|
+
Attribute,
|
|
54
|
+
FileContent,
|
|
55
|
+
FileStructure,
|
|
56
|
+
PathType,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
# Use as metadata keys and values for format descriptors
|
|
60
|
+
attrs = {
|
|
61
|
+
Attribute.PATH_TYPE: PathType.FILE,
|
|
62
|
+
Attribute.STRUCTURE: FileStructure.HDF5,
|
|
63
|
+
Attribute.CONTENT: FileContent.SOLVER_OUTPUTS,
|
|
64
|
+
Attribute.ANALYSIS_TYPE: AnalysisType.STRUCTURAL,
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
# Enum values are lowercase strings — usable with vcti-lookup rules
|
|
68
|
+
# Rule(Attribute.STRUCTURE.value, "==", FileStructure.HDF5.value)
|
|
69
|
+
|
|
70
|
+
# Lookup by value (useful for deserialization)
|
|
71
|
+
structure = FileStructure("hdf5")
|
|
72
|
+
assert structure is FileStructure.HDF5
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Enums
|
|
78
|
+
|
|
79
|
+
### Attribute
|
|
80
|
+
|
|
81
|
+
Attribute names for format descriptor metadata:
|
|
82
|
+
|
|
83
|
+
| Member | Value |
|
|
84
|
+
|--------|-------|
|
|
85
|
+
| `PATH_TYPE` | `"path_type"` |
|
|
86
|
+
| `SOLVER` | `"solver"` |
|
|
87
|
+
| `GENERATOR` | `"generator"` |
|
|
88
|
+
| `STRUCTURE` | `"structure"` |
|
|
89
|
+
| `CONTENT` | `"content"` |
|
|
90
|
+
| `ANALYSIS_TYPE` | `"analysis_type"` |
|
|
91
|
+
| `SOLUTION_TYPE` | `"solution_type"` |
|
|
92
|
+
|
|
93
|
+
### PathType
|
|
94
|
+
|
|
95
|
+
| Member | Value |
|
|
96
|
+
|--------|-------|
|
|
97
|
+
| `FILE` | `"file"` |
|
|
98
|
+
| `DIR` | `"dir"` |
|
|
99
|
+
|
|
100
|
+
### FileStructure
|
|
101
|
+
|
|
102
|
+
| Member | Value |
|
|
103
|
+
|--------|-------|
|
|
104
|
+
| `ASCII` | `"ascii"` |
|
|
105
|
+
| `BINARY` | `"binary"` |
|
|
106
|
+
| `HDF5` | `"hdf5"` |
|
|
107
|
+
| `JSON` | `"json"` |
|
|
108
|
+
| `CSV` | `"csv"` |
|
|
109
|
+
|
|
110
|
+
### FileContent
|
|
111
|
+
|
|
112
|
+
| Member | Value |
|
|
113
|
+
|--------|-------|
|
|
114
|
+
| `MESH` | `"mesh"` |
|
|
115
|
+
| `SOLVER_INPUTS` | `"solver_inputs"` |
|
|
116
|
+
| `SOLVER_OUTPUTS` | `"solver_outputs"` |
|
|
117
|
+
| `FILTERED_DATA` | `"filtered_data"` |
|
|
118
|
+
| `SURFACE_3D_MODEL` | `"surface_3d_model"` |
|
|
119
|
+
| `SURFACE_3D_VIEWS` | `"surface_3d_views"` |
|
|
120
|
+
|
|
121
|
+
### AnalysisType
|
|
122
|
+
|
|
123
|
+
| Member | Value |
|
|
124
|
+
|--------|-------|
|
|
125
|
+
| `STRUCTURAL` | `"structural"` |
|
|
126
|
+
| `THERMAL` | `"thermal"` |
|
|
127
|
+
| `FLUID` | `"fluid"` |
|
|
128
|
+
| `CRASH` | `"crash"` |
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Extending
|
|
133
|
+
|
|
134
|
+
To add a new member or a new enum, see [docs/extending.md](docs/extending.md).
|
|
135
|
+
All members use `auto_enum_value()` — values are always lowercase strings
|
|
136
|
+
derived from the member name.
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Dependencies
|
|
141
|
+
|
|
142
|
+
- [vcti-enum](https://pypi.org/project/vcti-enum/) (>=1.0.3) — value-generated string enums
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Path Format Attributes
|
|
2
|
+
|
|
3
|
+
Domain vocabulary enums for file format classification — path types, structures, content, and analysis categories.
|
|
4
|
+
|
|
5
|
+
Part of the path-format ecosystem:
|
|
6
|
+
**attributes** (this package) · **vcti-python-path-format** (framework) · **vcti-python-path-format-descriptors** (format plugins)
|
|
7
|
+
|
|
8
|
+
This package is the shared taxonomy — it defines the classification
|
|
9
|
+
dimensions that format descriptors and identification rules use. It lives
|
|
10
|
+
in its own repository so that vocabulary changes are deliberate and
|
|
11
|
+
reviewed across all formats. See [docs/ecosystem.md](docs/ecosystem.md)
|
|
12
|
+
for how the three repos work together, and
|
|
13
|
+
[docs/extending.md](docs/extending.md) for how to add new members and
|
|
14
|
+
enums.
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install vcti-path-format-attributes>=1.1.0
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### In `pyproject.toml` dependencies
|
|
23
|
+
|
|
24
|
+
```toml
|
|
25
|
+
dependencies = [
|
|
26
|
+
"vcti-path-format-attributes>=1.1.0",
|
|
27
|
+
]
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
from vcti.pathformat.attribute import (
|
|
36
|
+
AnalysisType,
|
|
37
|
+
Attribute,
|
|
38
|
+
FileContent,
|
|
39
|
+
FileStructure,
|
|
40
|
+
PathType,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# Use as metadata keys and values for format descriptors
|
|
44
|
+
attrs = {
|
|
45
|
+
Attribute.PATH_TYPE: PathType.FILE,
|
|
46
|
+
Attribute.STRUCTURE: FileStructure.HDF5,
|
|
47
|
+
Attribute.CONTENT: FileContent.SOLVER_OUTPUTS,
|
|
48
|
+
Attribute.ANALYSIS_TYPE: AnalysisType.STRUCTURAL,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
# Enum values are lowercase strings — usable with vcti-lookup rules
|
|
52
|
+
# Rule(Attribute.STRUCTURE.value, "==", FileStructure.HDF5.value)
|
|
53
|
+
|
|
54
|
+
# Lookup by value (useful for deserialization)
|
|
55
|
+
structure = FileStructure("hdf5")
|
|
56
|
+
assert structure is FileStructure.HDF5
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Enums
|
|
62
|
+
|
|
63
|
+
### Attribute
|
|
64
|
+
|
|
65
|
+
Attribute names for format descriptor metadata:
|
|
66
|
+
|
|
67
|
+
| Member | Value |
|
|
68
|
+
|--------|-------|
|
|
69
|
+
| `PATH_TYPE` | `"path_type"` |
|
|
70
|
+
| `SOLVER` | `"solver"` |
|
|
71
|
+
| `GENERATOR` | `"generator"` |
|
|
72
|
+
| `STRUCTURE` | `"structure"` |
|
|
73
|
+
| `CONTENT` | `"content"` |
|
|
74
|
+
| `ANALYSIS_TYPE` | `"analysis_type"` |
|
|
75
|
+
| `SOLUTION_TYPE` | `"solution_type"` |
|
|
76
|
+
|
|
77
|
+
### PathType
|
|
78
|
+
|
|
79
|
+
| Member | Value |
|
|
80
|
+
|--------|-------|
|
|
81
|
+
| `FILE` | `"file"` |
|
|
82
|
+
| `DIR` | `"dir"` |
|
|
83
|
+
|
|
84
|
+
### FileStructure
|
|
85
|
+
|
|
86
|
+
| Member | Value |
|
|
87
|
+
|--------|-------|
|
|
88
|
+
| `ASCII` | `"ascii"` |
|
|
89
|
+
| `BINARY` | `"binary"` |
|
|
90
|
+
| `HDF5` | `"hdf5"` |
|
|
91
|
+
| `JSON` | `"json"` |
|
|
92
|
+
| `CSV` | `"csv"` |
|
|
93
|
+
|
|
94
|
+
### FileContent
|
|
95
|
+
|
|
96
|
+
| Member | Value |
|
|
97
|
+
|--------|-------|
|
|
98
|
+
| `MESH` | `"mesh"` |
|
|
99
|
+
| `SOLVER_INPUTS` | `"solver_inputs"` |
|
|
100
|
+
| `SOLVER_OUTPUTS` | `"solver_outputs"` |
|
|
101
|
+
| `FILTERED_DATA` | `"filtered_data"` |
|
|
102
|
+
| `SURFACE_3D_MODEL` | `"surface_3d_model"` |
|
|
103
|
+
| `SURFACE_3D_VIEWS` | `"surface_3d_views"` |
|
|
104
|
+
|
|
105
|
+
### AnalysisType
|
|
106
|
+
|
|
107
|
+
| Member | Value |
|
|
108
|
+
|--------|-------|
|
|
109
|
+
| `STRUCTURAL` | `"structural"` |
|
|
110
|
+
| `THERMAL` | `"thermal"` |
|
|
111
|
+
| `FLUID` | `"fluid"` |
|
|
112
|
+
| `CRASH` | `"crash"` |
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Extending
|
|
117
|
+
|
|
118
|
+
To add a new member or a new enum, see [docs/extending.md](docs/extending.md).
|
|
119
|
+
All members use `auto_enum_value()` — values are always lowercase strings
|
|
120
|
+
derived from the member name.
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Dependencies
|
|
125
|
+
|
|
126
|
+
- [vcti-enum](https://pypi.org/project/vcti-enum/) (>=1.0.3) — value-generated string enums
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "vcti-path-format-attributes"
|
|
7
|
+
version = "1.1.0"
|
|
8
|
+
description = "Domain vocabulary enums for file format classification — path types, structures, content, and analysis categories"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
authors = [
|
|
11
|
+
{name = "Visual Collaboration Technologies Inc."}
|
|
12
|
+
]
|
|
13
|
+
requires-python = ">=3.12,<3.15"
|
|
14
|
+
dependencies = [
|
|
15
|
+
"vcti-enum>=1.0.3",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[project.optional-dependencies]
|
|
19
|
+
test = ["pytest", "pytest-cov"]
|
|
20
|
+
lint = ["ruff"]
|
|
21
|
+
|
|
22
|
+
[tool.setuptools.packages.find]
|
|
23
|
+
where = ["src"]
|
|
24
|
+
include = ["vcti.pathformat.attribute", "vcti.pathformat.attribute.*"]
|
|
25
|
+
|
|
26
|
+
[tool.setuptools.package-data]
|
|
27
|
+
"vcti.pathformat.attribute" = ["py.typed"]
|
|
28
|
+
|
|
29
|
+
[tool.setuptools]
|
|
30
|
+
zip-safe = true
|
|
31
|
+
|
|
32
|
+
[tool.pytest.ini_options]
|
|
33
|
+
addopts = "--cov=vcti.pathformat.attribute --cov-report=term-missing --cov-fail-under=95"
|
|
34
|
+
|
|
35
|
+
[tool.ruff]
|
|
36
|
+
target-version = "py312"
|
|
37
|
+
line-length = 99
|
|
38
|
+
|
|
39
|
+
[tool.ruff.lint]
|
|
40
|
+
select = ["E", "F", "W", "I", "UP"]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Copyright Visual Collaboration Technologies Inc. All Rights Reserved.
|
|
2
|
+
# See LICENSE for details.
|
|
3
|
+
"""vcti.pathformat.attribute — Domain vocabulary enums for file format classification."""
|
|
4
|
+
|
|
5
|
+
from importlib.metadata import version
|
|
6
|
+
|
|
7
|
+
from .analysis_type import AnalysisType
|
|
8
|
+
from .file_contents import FileContent
|
|
9
|
+
from .file_structure import FileStructure
|
|
10
|
+
from .names import Attribute
|
|
11
|
+
from .path_type import PathType
|
|
12
|
+
|
|
13
|
+
__version__ = version("vcti-path-format-attributes")
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"__version__",
|
|
17
|
+
"AnalysisType",
|
|
18
|
+
"Attribute",
|
|
19
|
+
"FileContent",
|
|
20
|
+
"FileStructure",
|
|
21
|
+
"PathType",
|
|
22
|
+
]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Copyright Visual Collaboration Technologies Inc. All Rights Reserved.
|
|
2
|
+
# See LICENSE for details.
|
|
3
|
+
"""Analysis type enum for classifying simulation analysis categories."""
|
|
4
|
+
|
|
5
|
+
from vcti.enum.value_generated_enums import EnumValueLowerCase, auto_enum_value
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AnalysisType(EnumValueLowerCase):
|
|
9
|
+
"""Enum of supported analysis types (structural, thermal, fluid, crash)."""
|
|
10
|
+
|
|
11
|
+
STRUCTURAL = auto_enum_value()
|
|
12
|
+
THERMAL = auto_enum_value()
|
|
13
|
+
FLUID = auto_enum_value()
|
|
14
|
+
CRASH = auto_enum_value()
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Copyright Visual Collaboration Technologies Inc. All Rights Reserved.
|
|
2
|
+
# See LICENSE for details.
|
|
3
|
+
"""File content type enum for classifying what a file contains."""
|
|
4
|
+
|
|
5
|
+
from vcti.enum.value_generated_enums import EnumValueLowerCase, auto_enum_value
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class FileContent(EnumValueLowerCase):
|
|
9
|
+
"""Enum of file content categories (mesh, solver inputs/outputs, 3D data)."""
|
|
10
|
+
|
|
11
|
+
MESH = auto_enum_value()
|
|
12
|
+
SOLVER_INPUTS = auto_enum_value()
|
|
13
|
+
SOLVER_OUTPUTS = auto_enum_value()
|
|
14
|
+
FILTERED_DATA = auto_enum_value()
|
|
15
|
+
SURFACE_3D_MODEL = auto_enum_value()
|
|
16
|
+
SURFACE_3D_VIEWS = auto_enum_value()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Copyright Visual Collaboration Technologies Inc. All Rights Reserved.
|
|
2
|
+
# See LICENSE for details.
|
|
3
|
+
"""File structure enum for classifying how data is organized."""
|
|
4
|
+
|
|
5
|
+
from vcti.enum.value_generated_enums import EnumValueLowerCase, auto_enum_value
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class FileStructure(EnumValueLowerCase):
|
|
9
|
+
"""Enum of file structure types (ASCII, binary, HDF5, JSON, CSV)."""
|
|
10
|
+
|
|
11
|
+
ASCII = auto_enum_value()
|
|
12
|
+
BINARY = auto_enum_value()
|
|
13
|
+
HDF5 = auto_enum_value()
|
|
14
|
+
JSON = auto_enum_value()
|
|
15
|
+
CSV = auto_enum_value()
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Copyright Visual Collaboration Technologies Inc. All Rights Reserved.
|
|
2
|
+
# See LICENSE for details.
|
|
3
|
+
"""Attribute names enum for format descriptor metadata keys."""
|
|
4
|
+
|
|
5
|
+
from vcti.enum.value_generated_enums import EnumValueLowerCase, auto_enum_value
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Attribute(EnumValueLowerCase):
|
|
9
|
+
"""Enum of format descriptor attribute names used for filtering and metadata."""
|
|
10
|
+
|
|
11
|
+
PATH_TYPE = auto_enum_value()
|
|
12
|
+
SOLVER = auto_enum_value()
|
|
13
|
+
GENERATOR = auto_enum_value()
|
|
14
|
+
STRUCTURE = auto_enum_value()
|
|
15
|
+
CONTENT = auto_enum_value()
|
|
16
|
+
ANALYSIS_TYPE = auto_enum_value()
|
|
17
|
+
SOLUTION_TYPE = auto_enum_value() # e.g. linear/nonlinear — how, vs ANALYSIS_TYPE's what
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Copyright Visual Collaboration Technologies Inc. All Rights Reserved.
|
|
2
|
+
# See LICENSE for details.
|
|
3
|
+
"""Path type enum distinguishing files from directories."""
|
|
4
|
+
|
|
5
|
+
from vcti.enum.value_generated_enums import EnumValueLowerCase, auto_enum_value
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class PathType(EnumValueLowerCase):
|
|
9
|
+
"""Enum distinguishing file paths from directory paths."""
|
|
10
|
+
|
|
11
|
+
FILE = auto_enum_value()
|
|
12
|
+
DIR = auto_enum_value()
|
|
File without changes
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vcti-path-format-attributes
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Domain vocabulary enums for file format classification — path types, structures, content, and analysis categories
|
|
5
|
+
Author: Visual Collaboration Technologies Inc.
|
|
6
|
+
Requires-Python: <3.15,>=3.12
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: vcti-enum>=1.0.3
|
|
10
|
+
Provides-Extra: test
|
|
11
|
+
Requires-Dist: pytest; extra == "test"
|
|
12
|
+
Requires-Dist: pytest-cov; extra == "test"
|
|
13
|
+
Provides-Extra: lint
|
|
14
|
+
Requires-Dist: ruff; extra == "lint"
|
|
15
|
+
Dynamic: license-file
|
|
16
|
+
|
|
17
|
+
# Path Format Attributes
|
|
18
|
+
|
|
19
|
+
Domain vocabulary enums for file format classification — path types, structures, content, and analysis categories.
|
|
20
|
+
|
|
21
|
+
Part of the path-format ecosystem:
|
|
22
|
+
**attributes** (this package) · **vcti-python-path-format** (framework) · **vcti-python-path-format-descriptors** (format plugins)
|
|
23
|
+
|
|
24
|
+
This package is the shared taxonomy — it defines the classification
|
|
25
|
+
dimensions that format descriptors and identification rules use. It lives
|
|
26
|
+
in its own repository so that vocabulary changes are deliberate and
|
|
27
|
+
reviewed across all formats. See [docs/ecosystem.md](docs/ecosystem.md)
|
|
28
|
+
for how the three repos work together, and
|
|
29
|
+
[docs/extending.md](docs/extending.md) for how to add new members and
|
|
30
|
+
enums.
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install vcti-path-format-attributes>=1.1.0
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### In `pyproject.toml` dependencies
|
|
39
|
+
|
|
40
|
+
```toml
|
|
41
|
+
dependencies = [
|
|
42
|
+
"vcti-path-format-attributes>=1.1.0",
|
|
43
|
+
]
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Quick Start
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from vcti.pathformat.attribute import (
|
|
52
|
+
AnalysisType,
|
|
53
|
+
Attribute,
|
|
54
|
+
FileContent,
|
|
55
|
+
FileStructure,
|
|
56
|
+
PathType,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
# Use as metadata keys and values for format descriptors
|
|
60
|
+
attrs = {
|
|
61
|
+
Attribute.PATH_TYPE: PathType.FILE,
|
|
62
|
+
Attribute.STRUCTURE: FileStructure.HDF5,
|
|
63
|
+
Attribute.CONTENT: FileContent.SOLVER_OUTPUTS,
|
|
64
|
+
Attribute.ANALYSIS_TYPE: AnalysisType.STRUCTURAL,
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
# Enum values are lowercase strings — usable with vcti-lookup rules
|
|
68
|
+
# Rule(Attribute.STRUCTURE.value, "==", FileStructure.HDF5.value)
|
|
69
|
+
|
|
70
|
+
# Lookup by value (useful for deserialization)
|
|
71
|
+
structure = FileStructure("hdf5")
|
|
72
|
+
assert structure is FileStructure.HDF5
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Enums
|
|
78
|
+
|
|
79
|
+
### Attribute
|
|
80
|
+
|
|
81
|
+
Attribute names for format descriptor metadata:
|
|
82
|
+
|
|
83
|
+
| Member | Value |
|
|
84
|
+
|--------|-------|
|
|
85
|
+
| `PATH_TYPE` | `"path_type"` |
|
|
86
|
+
| `SOLVER` | `"solver"` |
|
|
87
|
+
| `GENERATOR` | `"generator"` |
|
|
88
|
+
| `STRUCTURE` | `"structure"` |
|
|
89
|
+
| `CONTENT` | `"content"` |
|
|
90
|
+
| `ANALYSIS_TYPE` | `"analysis_type"` |
|
|
91
|
+
| `SOLUTION_TYPE` | `"solution_type"` |
|
|
92
|
+
|
|
93
|
+
### PathType
|
|
94
|
+
|
|
95
|
+
| Member | Value |
|
|
96
|
+
|--------|-------|
|
|
97
|
+
| `FILE` | `"file"` |
|
|
98
|
+
| `DIR` | `"dir"` |
|
|
99
|
+
|
|
100
|
+
### FileStructure
|
|
101
|
+
|
|
102
|
+
| Member | Value |
|
|
103
|
+
|--------|-------|
|
|
104
|
+
| `ASCII` | `"ascii"` |
|
|
105
|
+
| `BINARY` | `"binary"` |
|
|
106
|
+
| `HDF5` | `"hdf5"` |
|
|
107
|
+
| `JSON` | `"json"` |
|
|
108
|
+
| `CSV` | `"csv"` |
|
|
109
|
+
|
|
110
|
+
### FileContent
|
|
111
|
+
|
|
112
|
+
| Member | Value |
|
|
113
|
+
|--------|-------|
|
|
114
|
+
| `MESH` | `"mesh"` |
|
|
115
|
+
| `SOLVER_INPUTS` | `"solver_inputs"` |
|
|
116
|
+
| `SOLVER_OUTPUTS` | `"solver_outputs"` |
|
|
117
|
+
| `FILTERED_DATA` | `"filtered_data"` |
|
|
118
|
+
| `SURFACE_3D_MODEL` | `"surface_3d_model"` |
|
|
119
|
+
| `SURFACE_3D_VIEWS` | `"surface_3d_views"` |
|
|
120
|
+
|
|
121
|
+
### AnalysisType
|
|
122
|
+
|
|
123
|
+
| Member | Value |
|
|
124
|
+
|--------|-------|
|
|
125
|
+
| `STRUCTURAL` | `"structural"` |
|
|
126
|
+
| `THERMAL` | `"thermal"` |
|
|
127
|
+
| `FLUID` | `"fluid"` |
|
|
128
|
+
| `CRASH` | `"crash"` |
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Extending
|
|
133
|
+
|
|
134
|
+
To add a new member or a new enum, see [docs/extending.md](docs/extending.md).
|
|
135
|
+
All members use `auto_enum_value()` — values are always lowercase strings
|
|
136
|
+
derived from the member name.
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Dependencies
|
|
141
|
+
|
|
142
|
+
- [vcti-enum](https://pypi.org/project/vcti-enum/) (>=1.0.3) — value-generated string enums
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/vcti/pathformat/attribute/__init__.py
|
|
5
|
+
src/vcti/pathformat/attribute/analysis_type.py
|
|
6
|
+
src/vcti/pathformat/attribute/file_contents.py
|
|
7
|
+
src/vcti/pathformat/attribute/file_structure.py
|
|
8
|
+
src/vcti/pathformat/attribute/names.py
|
|
9
|
+
src/vcti/pathformat/attribute/path_type.py
|
|
10
|
+
src/vcti/pathformat/attribute/py.typed
|
|
11
|
+
src/vcti_path_format_attributes.egg-info/PKG-INFO
|
|
12
|
+
src/vcti_path_format_attributes.egg-info/SOURCES.txt
|
|
13
|
+
src/vcti_path_format_attributes.egg-info/dependency_links.txt
|
|
14
|
+
src/vcti_path_format_attributes.egg-info/requires.txt
|
|
15
|
+
src/vcti_path_format_attributes.egg-info/top_level.txt
|
|
16
|
+
src/vcti_path_format_attributes.egg-info/zip-safe
|
|
17
|
+
tests/test_attributes.py
|
|
18
|
+
tests/test_version.py
|
vcti_path_format_attributes-1.1.0/src/vcti_path_format_attributes.egg-info/dependency_links.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
vcti
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# Copyright Visual Collaboration Technologies Inc. All Rights Reserved.
|
|
2
|
+
# See LICENSE for details.
|
|
3
|
+
"""Tests for pathformat attribute enums.
|
|
4
|
+
|
|
5
|
+
Covers FileContent, FileStructure, PathType, AnalysisType, and Attribute —
|
|
6
|
+
verifying member presence, pinned auto-generated values, behavioral contracts
|
|
7
|
+
(lookup by value/name, hashing, iteration), and negative cases.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import pytest
|
|
11
|
+
|
|
12
|
+
from vcti.pathformat.attribute import (
|
|
13
|
+
AnalysisType,
|
|
14
|
+
Attribute,
|
|
15
|
+
FileContent,
|
|
16
|
+
FileStructure,
|
|
17
|
+
PathType,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
# ---------------------------------------------------------------------------
|
|
21
|
+
# FileContent
|
|
22
|
+
# ---------------------------------------------------------------------------
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class TestFileContent:
|
|
26
|
+
"""Tests for the FileContent enum."""
|
|
27
|
+
|
|
28
|
+
def test_has_six_members(self):
|
|
29
|
+
assert len(FileContent) == 6
|
|
30
|
+
|
|
31
|
+
def test_expected_members_exist(self):
|
|
32
|
+
assert hasattr(FileContent, "MESH")
|
|
33
|
+
assert hasattr(FileContent, "SOLVER_INPUTS")
|
|
34
|
+
assert hasattr(FileContent, "SOLVER_OUTPUTS")
|
|
35
|
+
assert hasattr(FileContent, "FILTERED_DATA")
|
|
36
|
+
assert hasattr(FileContent, "SURFACE_3D_MODEL")
|
|
37
|
+
assert hasattr(FileContent, "SURFACE_3D_VIEWS")
|
|
38
|
+
|
|
39
|
+
def test_pinned_values(self):
|
|
40
|
+
assert FileContent.MESH.value == "mesh"
|
|
41
|
+
assert FileContent.SOLVER_INPUTS.value == "solver_inputs"
|
|
42
|
+
assert FileContent.SOLVER_OUTPUTS.value == "solver_outputs"
|
|
43
|
+
assert FileContent.FILTERED_DATA.value == "filtered_data"
|
|
44
|
+
assert FileContent.SURFACE_3D_MODEL.value == "surface_3d_model"
|
|
45
|
+
assert FileContent.SURFACE_3D_VIEWS.value == "surface_3d_views"
|
|
46
|
+
|
|
47
|
+
def test_all_values_are_strings(self):
|
|
48
|
+
assert all(isinstance(m.value, str) for m in FileContent)
|
|
49
|
+
|
|
50
|
+
def test_all_values_are_distinct(self):
|
|
51
|
+
values = [m.value for m in FileContent]
|
|
52
|
+
assert len(values) == len(set(values))
|
|
53
|
+
|
|
54
|
+
def test_lookup_by_value(self):
|
|
55
|
+
assert FileContent("mesh") is FileContent.MESH
|
|
56
|
+
assert FileContent("surface_3d_model") is FileContent.SURFACE_3D_MODEL
|
|
57
|
+
|
|
58
|
+
def test_lookup_by_name(self):
|
|
59
|
+
assert FileContent["MESH"] is FileContent.MESH
|
|
60
|
+
assert FileContent["SURFACE_3D_VIEWS"] is FileContent.SURFACE_3D_VIEWS
|
|
61
|
+
|
|
62
|
+
def test_invalid_value_raises(self):
|
|
63
|
+
with pytest.raises(ValueError):
|
|
64
|
+
FileContent("nonexistent")
|
|
65
|
+
|
|
66
|
+
def test_invalid_name_raises(self):
|
|
67
|
+
with pytest.raises(KeyError):
|
|
68
|
+
FileContent["NONEXISTENT"]
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# ---------------------------------------------------------------------------
|
|
72
|
+
# FileStructure
|
|
73
|
+
# ---------------------------------------------------------------------------
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class TestFileStructure:
|
|
77
|
+
"""Tests for the FileStructure enum."""
|
|
78
|
+
|
|
79
|
+
def test_has_five_members(self):
|
|
80
|
+
assert len(FileStructure) == 5
|
|
81
|
+
|
|
82
|
+
def test_expected_members_exist(self):
|
|
83
|
+
assert hasattr(FileStructure, "ASCII")
|
|
84
|
+
assert hasattr(FileStructure, "BINARY")
|
|
85
|
+
assert hasattr(FileStructure, "HDF5")
|
|
86
|
+
assert hasattr(FileStructure, "JSON")
|
|
87
|
+
assert hasattr(FileStructure, "CSV")
|
|
88
|
+
|
|
89
|
+
def test_pinned_values(self):
|
|
90
|
+
assert FileStructure.ASCII.value == "ascii"
|
|
91
|
+
assert FileStructure.BINARY.value == "binary"
|
|
92
|
+
assert FileStructure.HDF5.value == "hdf5"
|
|
93
|
+
assert FileStructure.JSON.value == "json"
|
|
94
|
+
assert FileStructure.CSV.value == "csv"
|
|
95
|
+
|
|
96
|
+
def test_all_values_are_strings(self):
|
|
97
|
+
assert all(isinstance(m.value, str) for m in FileStructure)
|
|
98
|
+
|
|
99
|
+
def test_all_values_are_distinct(self):
|
|
100
|
+
values = [m.value for m in FileStructure]
|
|
101
|
+
assert len(values) == len(set(values))
|
|
102
|
+
|
|
103
|
+
def test_lookup_by_value(self):
|
|
104
|
+
assert FileStructure("hdf5") is FileStructure.HDF5
|
|
105
|
+
|
|
106
|
+
def test_lookup_by_name(self):
|
|
107
|
+
assert FileStructure["HDF5"] is FileStructure.HDF5
|
|
108
|
+
|
|
109
|
+
def test_invalid_value_raises(self):
|
|
110
|
+
with pytest.raises(ValueError):
|
|
111
|
+
FileStructure("xml")
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
# ---------------------------------------------------------------------------
|
|
115
|
+
# PathType
|
|
116
|
+
# ---------------------------------------------------------------------------
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class TestPathType:
|
|
120
|
+
"""Tests for the PathType enum."""
|
|
121
|
+
|
|
122
|
+
def test_has_two_members(self):
|
|
123
|
+
assert len(PathType) == 2
|
|
124
|
+
|
|
125
|
+
def test_expected_members_exist(self):
|
|
126
|
+
assert hasattr(PathType, "FILE")
|
|
127
|
+
assert hasattr(PathType, "DIR")
|
|
128
|
+
|
|
129
|
+
def test_pinned_values(self):
|
|
130
|
+
assert PathType.FILE.value == "file"
|
|
131
|
+
assert PathType.DIR.value == "dir"
|
|
132
|
+
|
|
133
|
+
def test_all_values_are_strings(self):
|
|
134
|
+
assert all(isinstance(m.value, str) for m in PathType)
|
|
135
|
+
|
|
136
|
+
def test_lookup_by_value(self):
|
|
137
|
+
assert PathType("file") is PathType.FILE
|
|
138
|
+
assert PathType("dir") is PathType.DIR
|
|
139
|
+
|
|
140
|
+
def test_invalid_value_raises(self):
|
|
141
|
+
with pytest.raises(ValueError):
|
|
142
|
+
PathType("symlink")
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
# ---------------------------------------------------------------------------
|
|
146
|
+
# AnalysisType
|
|
147
|
+
# ---------------------------------------------------------------------------
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class TestAnalysisType:
|
|
151
|
+
"""Tests for the AnalysisType enum."""
|
|
152
|
+
|
|
153
|
+
def test_has_four_members(self):
|
|
154
|
+
assert len(AnalysisType) == 4
|
|
155
|
+
|
|
156
|
+
def test_expected_members_exist(self):
|
|
157
|
+
assert hasattr(AnalysisType, "STRUCTURAL")
|
|
158
|
+
assert hasattr(AnalysisType, "THERMAL")
|
|
159
|
+
assert hasattr(AnalysisType, "FLUID")
|
|
160
|
+
assert hasattr(AnalysisType, "CRASH")
|
|
161
|
+
|
|
162
|
+
def test_pinned_values(self):
|
|
163
|
+
assert AnalysisType.STRUCTURAL.value == "structural"
|
|
164
|
+
assert AnalysisType.THERMAL.value == "thermal"
|
|
165
|
+
assert AnalysisType.FLUID.value == "fluid"
|
|
166
|
+
assert AnalysisType.CRASH.value == "crash"
|
|
167
|
+
|
|
168
|
+
def test_all_values_are_strings(self):
|
|
169
|
+
assert all(isinstance(m.value, str) for m in AnalysisType)
|
|
170
|
+
|
|
171
|
+
def test_all_values_are_distinct(self):
|
|
172
|
+
values = [m.value for m in AnalysisType]
|
|
173
|
+
assert len(values) == len(set(values))
|
|
174
|
+
|
|
175
|
+
def test_lookup_by_value(self):
|
|
176
|
+
assert AnalysisType("structural") is AnalysisType.STRUCTURAL
|
|
177
|
+
|
|
178
|
+
def test_invalid_value_raises(self):
|
|
179
|
+
with pytest.raises(ValueError):
|
|
180
|
+
AnalysisType("electromagnetic")
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
# ---------------------------------------------------------------------------
|
|
184
|
+
# Attribute
|
|
185
|
+
# ---------------------------------------------------------------------------
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
class TestAttribute:
|
|
189
|
+
"""Tests for the Attribute (attribute names) enum."""
|
|
190
|
+
|
|
191
|
+
def test_has_seven_members(self):
|
|
192
|
+
assert len(Attribute) == 7
|
|
193
|
+
|
|
194
|
+
def test_expected_members_exist(self):
|
|
195
|
+
assert hasattr(Attribute, "PATH_TYPE")
|
|
196
|
+
assert hasattr(Attribute, "SOLVER")
|
|
197
|
+
assert hasattr(Attribute, "GENERATOR")
|
|
198
|
+
assert hasattr(Attribute, "STRUCTURE")
|
|
199
|
+
assert hasattr(Attribute, "CONTENT")
|
|
200
|
+
assert hasattr(Attribute, "ANALYSIS_TYPE")
|
|
201
|
+
assert hasattr(Attribute, "SOLUTION_TYPE")
|
|
202
|
+
|
|
203
|
+
def test_pinned_values(self):
|
|
204
|
+
assert Attribute.PATH_TYPE.value == "path_type"
|
|
205
|
+
assert Attribute.SOLVER.value == "solver"
|
|
206
|
+
assert Attribute.GENERATOR.value == "generator"
|
|
207
|
+
assert Attribute.STRUCTURE.value == "structure"
|
|
208
|
+
assert Attribute.CONTENT.value == "content"
|
|
209
|
+
assert Attribute.ANALYSIS_TYPE.value == "analysis_type"
|
|
210
|
+
assert Attribute.SOLUTION_TYPE.value == "solution_type"
|
|
211
|
+
|
|
212
|
+
def test_all_values_are_strings(self):
|
|
213
|
+
assert all(isinstance(m.value, str) for m in Attribute)
|
|
214
|
+
|
|
215
|
+
def test_all_values_are_distinct(self):
|
|
216
|
+
values = [m.value for m in Attribute]
|
|
217
|
+
assert len(values) == len(set(values))
|
|
218
|
+
|
|
219
|
+
def test_lookup_by_value(self):
|
|
220
|
+
assert Attribute("path_type") is Attribute.PATH_TYPE
|
|
221
|
+
|
|
222
|
+
def test_lookup_by_name(self):
|
|
223
|
+
assert Attribute["ANALYSIS_TYPE"] is Attribute.ANALYSIS_TYPE
|
|
224
|
+
|
|
225
|
+
def test_invalid_value_raises(self):
|
|
226
|
+
with pytest.raises(ValueError):
|
|
227
|
+
Attribute("nonexistent")
|
|
228
|
+
|
|
229
|
+
def test_values_usable_as_dict_keys(self):
|
|
230
|
+
d = {Attribute.PATH_TYPE: "file", Attribute.STRUCTURE: "binary"}
|
|
231
|
+
assert len(d) == 2
|
|
232
|
+
|
|
233
|
+
def test_members_usable_as_dict_keys(self):
|
|
234
|
+
d = {Attribute.PATH_TYPE: PathType.FILE, Attribute.STRUCTURE: FileStructure.HDF5}
|
|
235
|
+
assert d[Attribute.PATH_TYPE] is PathType.FILE
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
# ---------------------------------------------------------------------------
|
|
239
|
+
# Cross-enum contracts
|
|
240
|
+
# ---------------------------------------------------------------------------
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
class TestCrossEnumContracts:
|
|
244
|
+
"""Tests for invariants that span multiple enums."""
|
|
245
|
+
|
|
246
|
+
def test_all_enums_use_lowercase_string_values(self):
|
|
247
|
+
"""Every auto-generated value must be a lowercase string."""
|
|
248
|
+
for enum_cls in (Attribute, PathType, FileStructure, FileContent, AnalysisType):
|
|
249
|
+
for member in enum_cls:
|
|
250
|
+
assert member.value == member.value.lower(), (
|
|
251
|
+
f"{enum_cls.__name__}.{member.name} value {member.value!r} is not lowercase"
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
def test_attribute_values_do_not_collide_with_enum_values(self):
|
|
255
|
+
"""Attribute keys must not collide with any value enum member values."""
|
|
256
|
+
attr_values = {m.value for m in Attribute}
|
|
257
|
+
for enum_cls in (PathType, FileStructure, FileContent, AnalysisType):
|
|
258
|
+
enum_values = {m.value for m in enum_cls}
|
|
259
|
+
collision = attr_values & enum_values
|
|
260
|
+
assert not collision, f"Attribute values collide with {enum_cls.__name__}: {collision}"
|
|
261
|
+
|
|
262
|
+
def test_all_enums_are_hashable(self):
|
|
263
|
+
"""All enum members must be usable as dict keys and set members."""
|
|
264
|
+
for enum_cls in (Attribute, PathType, FileStructure, FileContent, AnalysisType):
|
|
265
|
+
members_set = set(enum_cls)
|
|
266
|
+
assert len(members_set) == len(enum_cls)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Copyright Visual Collaboration Technologies Inc. All Rights Reserved.
|
|
2
|
+
# See LICENSE for details.
|
|
3
|
+
"""Version tests for vcti-path-format-attributes."""
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
import vcti.pathformat.attribute
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestVersion:
|
|
11
|
+
def test_version_exists(self):
|
|
12
|
+
assert hasattr(vcti.pathformat.attribute, "__version__")
|
|
13
|
+
|
|
14
|
+
def test_version_is_valid_semver(self):
|
|
15
|
+
assert re.match(r"^\d+\.\d+\.\d+", vcti.pathformat.attribute.__version__)
|