varda 0.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.
varda-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mark Luttikhof
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
varda-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,206 @@
1
+ Metadata-Version: 2.4
2
+ Name: varda
3
+ Version: 0.1.0
4
+ Summary: Dimensional modeling for LinkML — a profile, its rules, and the generators that hang off it
5
+ License-Expression: MIT
6
+ Project-URL: Homepage, https://github.com/mluttikh/varda
7
+ Project-URL: Documentation, https://mluttikh.github.io/varda/
8
+ Project-URL: Source, https://github.com/mluttikh/varda
9
+ Keywords: linkml,dimensional-modeling,star-schema,kimball,data-warehouse,data-mart,metadata
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Programming Language :: Python :: 3.14
16
+ Classifier: Topic :: Database
17
+ Classifier: Topic :: Software Development :: Code Generators
18
+ Classifier: Typing :: Typed
19
+ Requires-Python: >=3.11
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: linkml-runtime>=1.9
23
+ Provides-Extra: dev
24
+ Requires-Dist: pytest>=8; extra == "dev"
25
+ Requires-Dist: mypy>=1.11; extra == "dev"
26
+ Requires-Dist: ruff>=0.6; extra == "dev"
27
+ Requires-Dist: pyyaml>=6; extra == "dev"
28
+ Requires-Dist: types-PyYAML>=6; extra == "dev"
29
+ Requires-Dist: build>=1; extra == "dev"
30
+ Requires-Dist: twine>=5; extra == "dev"
31
+ Requires-Dist: actionlint-py>=1.7; extra == "dev"
32
+ Provides-Extra: docs
33
+ Requires-Dist: mkdocs-material>=9.5; extra == "docs"
34
+ Requires-Dist: mkdocs<2,>=1.6; extra == "docs"
35
+ Dynamic: license-file
36
+
37
+ # Varda
38
+
39
+ [![CI](https://github.com/mluttikh/varda/actions/workflows/ci.yml/badge.svg)](https://github.com/mluttikh/varda/actions/workflows/ci.yml)
40
+ [![PyPI](https://img.shields.io/pypi/v/varda)](https://pypi.org/project/varda/)
41
+ [![Python](https://img.shields.io/pypi/pyversions/varda)](https://pypi.org/project/varda/)
42
+ [![Docs](https://img.shields.io/badge/docs-mluttikh.github.io%2Fvarda-2F6B57)](https://mluttikh.github.io/varda/)
43
+
44
+ **Dimensional modeling for [LinkML](https://linkml.io).**
45
+
46
+ Varda is a *profile* of LinkML: a small vocabulary that lets you say a class
47
+ is a fact table, that a column is a semi-additive measure, that a dimension
48
+ keeps history. It then checks those claims and generates from them.
49
+
50
+ A model annotated with Varda is still an ordinary LinkML schema. Every other
51
+ LinkML tool — `gen-pydantic`, `gen-owl`, `gen-json-schema` — will read it
52
+ happily and ignore what it does not understand.
53
+
54
+ ```yaml
55
+ FctSale:
56
+ annotations:
57
+ varda:role: fact
58
+ varda:fact_type: transaction
59
+ varda:grain: one row per product per line of a sales receipt
60
+ attributes:
61
+ customer_key:
62
+ range: integer
63
+ annotations:
64
+ varda:role: foreign_key
65
+ varda:references: DimCustomer
66
+ net_amount:
67
+ range: decimal
68
+ annotations:
69
+ varda:role: measure
70
+ varda:additivity: additive
71
+ varda:unit: EUR
72
+ ```
73
+
74
+ ```console
75
+ $ varda check model.yaml
76
+ 8 tables checked against 22 rules (varda 0.1.0): 0 errors, 0 warnings
77
+
78
+ $ varda generate model.yaml --out out/
79
+ wrote out/docs/model.md
80
+ wrote out/sql/mart.sql
81
+ ```
82
+
83
+ ## Install
84
+
85
+ ```console
86
+ pip install varda
87
+ ```
88
+
89
+ Python 3.11+. The only runtime dependency is `linkml-runtime`.
90
+
91
+ ## What it gives you
92
+
93
+ **Eleven annotations.** Five on tables — `role`, `grain`, `fact_type`, `scd`,
94
+ `physical_name`. Six on columns — `role`, `references`, `additivity`,
95
+ `semi_additive_over`, `unit`, `physical_name`. That is the whole core
96
+ vocabulary, and it is deliberately the whole core vocabulary.
97
+
98
+ **Twenty-two rules** that catch the mistakes worth catching:
99
+
100
+ | | |
101
+ | --- | --- |
102
+ | `V001`–`V003` | the annotations themselves — typos, bad enum values, unknown prefixes |
103
+ | `V101`–`V113` | structure — a fact without a grain, a foreign key pointing at a fact, a dimension with no natural key |
104
+ | `V201`–`V206` | measures — an unclassified measure, a semi-additive one that never says what it cannot cross |
105
+
106
+ The `V2xx` family exists because additivity is where the expensive errors
107
+ live. A structural mistake usually breaks a query. An additivity mistake
108
+ returns a number that looks entirely reasonable and is wrong, to someone who
109
+ will act on it.
110
+
111
+ **Two generators**, `sql` and `docs`, producing runnable DDL and a Markdown
112
+ reference. Both are deterministic: no timestamps, no environment, same model
113
+ in and same bytes out, so the output can be committed and diffed.
114
+
115
+ ## Extending it
116
+
117
+ Varda's core is small on purpose. Anything specific to how *your*
118
+ organization works — cost centers, retention, data classification, ownership
119
+ — goes in an extension under your own prefix.
120
+
121
+ The smallest useful extension needs no Python at all. Write a LinkML schema
122
+ declaring your vocabulary, then a `varda.toml`:
123
+
124
+ ```toml
125
+ [[extension]]
126
+ name = "acme"
127
+ prefix = "acme"
128
+ profile = "profiles/acme.yaml"
129
+ ```
130
+
131
+ From then on `acme:cost_center` is a first-class annotation: checked for
132
+ typos, its enum values enforced, and listed by `varda ext`. Misspell it and
133
+ you get
134
+
135
+ ```
136
+ ERROR V001 DimStore
137
+ unknown table annotation 'acme:cost_center'; declare it in
138
+ acme.yaml or fix the typo
139
+ ```
140
+
141
+ Full documentation: **<https://mluttikh.github.io/varda/>**
142
+
143
+ An extension with code behind it adds rules and generators through
144
+ `varda.ext`, and ships as an installable package advertising the
145
+ `varda.extensions` entry point. See [`SPEC.md`](SPEC.md) for the interface
146
+ and `tests/fixtures/acme_ext/` for a complete worked example.
147
+
148
+ **One party, one namespace; extensions add, they never redefine.** An
149
+ extension may introduce annotations, enums and rules under its own prefix. It
150
+ may not add a value to `TableRole` or change what `semi_additive` means —
151
+ every generator dispatches exhaustively on those, and the registry refuses at
152
+ load rather than warning.
153
+
154
+ ## Commands
155
+
156
+ | | |
157
+ | --- | --- |
158
+ | `varda check MODEL` | validate; `--strict` fails on warnings too |
159
+ | `varda generate MODEL --out DIR` | write artifacts; fails closed |
160
+ | `varda rules` | list every rule, `-v` for reasoning |
161
+ | `varda ext` | describe active extensions and their vocabulary |
162
+ | `varda importmap` | print the LinkML import map |
163
+
164
+ Exit codes are part of the contract: `0` success, `1` the model or run
165
+ failed, `2` the invocation was wrong.
166
+
167
+ ## Status
168
+
169
+ **0.1.0 — alpha.** The vocabulary and rule codes are stable enough to build
170
+ on; rule codes will not be renumbered. Analytical functions, model diffing,
171
+ lineage and the drift gate are deliberately not here yet — see `SPEC.md` for
172
+ what is deferred and why.
173
+
174
+ ## Building the documentation
175
+
176
+ ```console
177
+ pip install -e ".[docs]"
178
+ mkdocs serve
179
+ ```
180
+
181
+ Then open **<http://127.0.0.1:8000/varda/>** — note the `/varda/` path, which
182
+ comes from `site_url` because this is a GitHub Pages project site rather than
183
+ a user site. Plain `http://127.0.0.1:8000/` redirects there.
184
+
185
+ The vocabulary, rules and command-line pages are generated from the package
186
+ itself into a git-ignored `docs/reference/`, so they cannot drift from the
187
+ code. `mkdocs serve` regenerates them on every rebuild and watches `src/` as
188
+ well as `docs/` — edit a rule's docstring and the page updates.
189
+
190
+ To build the static site the way CI does:
191
+
192
+ ```console
193
+ python scripts/gen_reference.py
194
+ mkdocs build --strict
195
+ ```
196
+
197
+ `--strict` turns a broken internal link into a failed build. The generator is
198
+ a standalone script rather than a plugin, so the site also builds under
199
+ [Zensical](https://zensical.org) and [ProperDocs](https://properdocs.org) from
200
+ the same `mkdocs.yml` — see `docs/design.md` for why that matters.
201
+
202
+ ## License
203
+
204
+ MIT for the code. The profile vocabulary in `src/varda/profile/varda.yaml` is
205
+ CC0, so it can be reused anywhere without attribution — a vocabulary that
206
+ constrains its own reuse is not much of a vocabulary.
varda-0.1.0/README.md ADDED
@@ -0,0 +1,170 @@
1
+ # Varda
2
+
3
+ [![CI](https://github.com/mluttikh/varda/actions/workflows/ci.yml/badge.svg)](https://github.com/mluttikh/varda/actions/workflows/ci.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/varda)](https://pypi.org/project/varda/)
5
+ [![Python](https://img.shields.io/pypi/pyversions/varda)](https://pypi.org/project/varda/)
6
+ [![Docs](https://img.shields.io/badge/docs-mluttikh.github.io%2Fvarda-2F6B57)](https://mluttikh.github.io/varda/)
7
+
8
+ **Dimensional modeling for [LinkML](https://linkml.io).**
9
+
10
+ Varda is a *profile* of LinkML: a small vocabulary that lets you say a class
11
+ is a fact table, that a column is a semi-additive measure, that a dimension
12
+ keeps history. It then checks those claims and generates from them.
13
+
14
+ A model annotated with Varda is still an ordinary LinkML schema. Every other
15
+ LinkML tool — `gen-pydantic`, `gen-owl`, `gen-json-schema` — will read it
16
+ happily and ignore what it does not understand.
17
+
18
+ ```yaml
19
+ FctSale:
20
+ annotations:
21
+ varda:role: fact
22
+ varda:fact_type: transaction
23
+ varda:grain: one row per product per line of a sales receipt
24
+ attributes:
25
+ customer_key:
26
+ range: integer
27
+ annotations:
28
+ varda:role: foreign_key
29
+ varda:references: DimCustomer
30
+ net_amount:
31
+ range: decimal
32
+ annotations:
33
+ varda:role: measure
34
+ varda:additivity: additive
35
+ varda:unit: EUR
36
+ ```
37
+
38
+ ```console
39
+ $ varda check model.yaml
40
+ 8 tables checked against 22 rules (varda 0.1.0): 0 errors, 0 warnings
41
+
42
+ $ varda generate model.yaml --out out/
43
+ wrote out/docs/model.md
44
+ wrote out/sql/mart.sql
45
+ ```
46
+
47
+ ## Install
48
+
49
+ ```console
50
+ pip install varda
51
+ ```
52
+
53
+ Python 3.11+. The only runtime dependency is `linkml-runtime`.
54
+
55
+ ## What it gives you
56
+
57
+ **Eleven annotations.** Five on tables — `role`, `grain`, `fact_type`, `scd`,
58
+ `physical_name`. Six on columns — `role`, `references`, `additivity`,
59
+ `semi_additive_over`, `unit`, `physical_name`. That is the whole core
60
+ vocabulary, and it is deliberately the whole core vocabulary.
61
+
62
+ **Twenty-two rules** that catch the mistakes worth catching:
63
+
64
+ | | |
65
+ | --- | --- |
66
+ | `V001`–`V003` | the annotations themselves — typos, bad enum values, unknown prefixes |
67
+ | `V101`–`V113` | structure — a fact without a grain, a foreign key pointing at a fact, a dimension with no natural key |
68
+ | `V201`–`V206` | measures — an unclassified measure, a semi-additive one that never says what it cannot cross |
69
+
70
+ The `V2xx` family exists because additivity is where the expensive errors
71
+ live. A structural mistake usually breaks a query. An additivity mistake
72
+ returns a number that looks entirely reasonable and is wrong, to someone who
73
+ will act on it.
74
+
75
+ **Two generators**, `sql` and `docs`, producing runnable DDL and a Markdown
76
+ reference. Both are deterministic: no timestamps, no environment, same model
77
+ in and same bytes out, so the output can be committed and diffed.
78
+
79
+ ## Extending it
80
+
81
+ Varda's core is small on purpose. Anything specific to how *your*
82
+ organization works — cost centers, retention, data classification, ownership
83
+ — goes in an extension under your own prefix.
84
+
85
+ The smallest useful extension needs no Python at all. Write a LinkML schema
86
+ declaring your vocabulary, then a `varda.toml`:
87
+
88
+ ```toml
89
+ [[extension]]
90
+ name = "acme"
91
+ prefix = "acme"
92
+ profile = "profiles/acme.yaml"
93
+ ```
94
+
95
+ From then on `acme:cost_center` is a first-class annotation: checked for
96
+ typos, its enum values enforced, and listed by `varda ext`. Misspell it and
97
+ you get
98
+
99
+ ```
100
+ ERROR V001 DimStore
101
+ unknown table annotation 'acme:cost_center'; declare it in
102
+ acme.yaml or fix the typo
103
+ ```
104
+
105
+ Full documentation: **<https://mluttikh.github.io/varda/>**
106
+
107
+ An extension with code behind it adds rules and generators through
108
+ `varda.ext`, and ships as an installable package advertising the
109
+ `varda.extensions` entry point. See [`SPEC.md`](SPEC.md) for the interface
110
+ and `tests/fixtures/acme_ext/` for a complete worked example.
111
+
112
+ **One party, one namespace; extensions add, they never redefine.** An
113
+ extension may introduce annotations, enums and rules under its own prefix. It
114
+ may not add a value to `TableRole` or change what `semi_additive` means —
115
+ every generator dispatches exhaustively on those, and the registry refuses at
116
+ load rather than warning.
117
+
118
+ ## Commands
119
+
120
+ | | |
121
+ | --- | --- |
122
+ | `varda check MODEL` | validate; `--strict` fails on warnings too |
123
+ | `varda generate MODEL --out DIR` | write artifacts; fails closed |
124
+ | `varda rules` | list every rule, `-v` for reasoning |
125
+ | `varda ext` | describe active extensions and their vocabulary |
126
+ | `varda importmap` | print the LinkML import map |
127
+
128
+ Exit codes are part of the contract: `0` success, `1` the model or run
129
+ failed, `2` the invocation was wrong.
130
+
131
+ ## Status
132
+
133
+ **0.1.0 — alpha.** The vocabulary and rule codes are stable enough to build
134
+ on; rule codes will not be renumbered. Analytical functions, model diffing,
135
+ lineage and the drift gate are deliberately not here yet — see `SPEC.md` for
136
+ what is deferred and why.
137
+
138
+ ## Building the documentation
139
+
140
+ ```console
141
+ pip install -e ".[docs]"
142
+ mkdocs serve
143
+ ```
144
+
145
+ Then open **<http://127.0.0.1:8000/varda/>** — note the `/varda/` path, which
146
+ comes from `site_url` because this is a GitHub Pages project site rather than
147
+ a user site. Plain `http://127.0.0.1:8000/` redirects there.
148
+
149
+ The vocabulary, rules and command-line pages are generated from the package
150
+ itself into a git-ignored `docs/reference/`, so they cannot drift from the
151
+ code. `mkdocs serve` regenerates them on every rebuild and watches `src/` as
152
+ well as `docs/` — edit a rule's docstring and the page updates.
153
+
154
+ To build the static site the way CI does:
155
+
156
+ ```console
157
+ python scripts/gen_reference.py
158
+ mkdocs build --strict
159
+ ```
160
+
161
+ `--strict` turns a broken internal link into a failed build. The generator is
162
+ a standalone script rather than a plugin, so the site also builds under
163
+ [Zensical](https://zensical.org) and [ProperDocs](https://properdocs.org) from
164
+ the same `mkdocs.yml` — see `docs/design.md` for why that matters.
165
+
166
+ ## License
167
+
168
+ MIT for the code. The profile vocabulary in `src/varda/profile/varda.yaml` is
169
+ CC0, so it can be reused anywhere without attribution — a vocabulary that
170
+ constrains its own reuse is not much of a vocabulary.
@@ -0,0 +1,212 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "varda"
7
+
8
+ # The version lives in `src/varda/__init__.py` and is read from there, rather
9
+ # than being declared here and repeated in the package. Two copies of a
10
+ # version number drift the first time somebody bumps one of them, and the
11
+ # failure is quiet: `varda check` prints `__version__` in its summary line, so
12
+ # a package would misreport itself to every user while the distribution
13
+ # metadata said something else. One source removes the class of mistake
14
+ # instead of adding a test that notices it afterwards.
15
+ dynamic = ["version"]
16
+ description = "Dimensional modeling for LinkML — a profile, its rules, and the generators that hang off it"
17
+ readme = "README.md"
18
+ requires-python = ">=3.11"
19
+ license = "MIT"
20
+ keywords = [
21
+ "linkml",
22
+ "dimensional-modeling",
23
+ "star-schema",
24
+ "kimball",
25
+ "data-warehouse",
26
+ "data-mart",
27
+ "metadata",
28
+ ]
29
+ classifiers = [
30
+ "Development Status :: 3 - Alpha",
31
+ "Intended Audience :: Developers",
32
+ "Programming Language :: Python :: 3.11",
33
+ "Programming Language :: Python :: 3.12",
34
+ "Programming Language :: Python :: 3.13",
35
+ "Programming Language :: Python :: 3.14",
36
+ "Topic :: Database",
37
+ "Topic :: Software Development :: Code Generators",
38
+ "Typing :: Typed",
39
+ ]
40
+
41
+ # Only linkml-runtime. The full `linkml` distribution pulls a large tree in
42
+ # order to provide generators, and Varda's generators are hand-written against
43
+ # the model layer rather than against LinkML's generator framework. A minimal
44
+ # dependency set is most of what makes this installable inside somebody else's
45
+ # pipeline without an argument.
46
+ dependencies = ["linkml-runtime>=1.9"]
47
+
48
+ [project.optional-dependencies]
49
+ dev = [
50
+ "pytest>=8",
51
+ "mypy>=1.11",
52
+ "ruff>=0.6",
53
+ "pyyaml>=6",
54
+ "types-PyYAML>=6",
55
+ "build>=1",
56
+ "twine>=5",
57
+ # Vendors the actionlint binary. The workflows are code that only
58
+ # ever runs on a push, so a mistake in them is otherwise found by
59
+ # pushing a broken one and reading the failure.
60
+ "actionlint-py>=1.7",
61
+ ]
62
+ docs = [
63
+ "mkdocs-material>=9.5",
64
+ # Pinned below 2.0 deliberately. MkDocs last shipped 1.6.1 in August
65
+ # 2024, and its maintainer has announced a 2.0 that will not support
66
+ # existing themes, plugins or config files. An unpinned `mkdocs` could
67
+ # therefore break the docs build without a change on our side.
68
+ #
69
+ # `properdocs`, a maintained continuation of 1.x, has been verified as a
70
+ # drop-in: `properdocs build --strict` produces an identical site from
71
+ # this same mkdocs.yml. If 2.0 lands and the pin becomes untenable, that
72
+ # is the migration, and it is a one-line change here.
73
+ "mkdocs>=1.6,<2",
74
+ ]
75
+
76
+ [project.urls]
77
+ Homepage = "https://github.com/mluttikh/varda"
78
+ Documentation = "https://mluttikh.github.io/varda/"
79
+ Source = "https://github.com/mluttikh/varda"
80
+
81
+ [project.scripts]
82
+ varda = "varda.cli:main"
83
+
84
+ [project.entry-points."varda.extensions"]
85
+ # Extensions register here. Varda itself does not — it is built in, so that
86
+ # the core is present even when nothing else is installed.
87
+
88
+ [tool.setuptools.packages.find]
89
+ where = ["src"]
90
+
91
+ [tool.setuptools.dynamic]
92
+ version = { attr = "varda.__version__" }
93
+
94
+ # Ships the type information. An extension author's own type checker then sees
95
+ # the boundary Varda maintains: `model.py` is the wall built along the untyped
96
+ # LinkML runtime, and everything it returns is a concrete type.
97
+ [tool.setuptools.package-data]
98
+ varda = ["py.typed", "profile/*.yaml"]
99
+
100
+ [tool.pytest.ini_options]
101
+ testpaths = ["tests"]
102
+
103
+ [tool.mypy]
104
+ python_version = "3.11"
105
+ files = ["src/varda", "tests", "scripts"]
106
+ strict = true
107
+
108
+ # LinkML ships no `py.typed`, so every object out of `SchemaView` is `Any`.
109
+ # That is not a defect to suppress and forget: it is the boundary of the typed
110
+ # world, and `varda/model.py` is the wall built along it.
111
+ #
112
+ # `warn_return_any` is the rule doing the work. It fires whenever an `Any`
113
+ # escapes into a signature claiming something specific, which is exactly the
114
+ # mistake this arrangement exists to catch. Do not switch it off to make a
115
+ # stubborn line pass.
116
+ [[tool.mypy.overrides]]
117
+ module = ["linkml_runtime.*", "jsonasobj2"]
118
+ ignore_missing_imports = true
119
+
120
+ [tool.ruff]
121
+ line-length = 80
122
+ extend-exclude = ["out"]
123
+
124
+ [tool.ruff.lint]
125
+ select = [
126
+ "A", # flake8-builtins
127
+ "ARG", # unused-function-argument
128
+ "B", # flake8-bugbear
129
+ "BLE", # flake8-blind-except
130
+ "C4", # comprehensions
131
+ "C90", # mccabe
132
+ "D", # pydocstyle
133
+ "E", # pycodestyle
134
+ "EM", # flake8-errmsg
135
+ "ERA", # eradicate
136
+ "F", # pyflakes
137
+ "FA", # flake8-future-annotations
138
+ "FLY", # flynt
139
+ "FURB", # refurb
140
+ "G", # flake8-logging-format
141
+ "I", # isort
142
+ "ICN", # flake8-import-conventions
143
+ "INP", # flake8-no-pep420
144
+ "ISC", # flake8-implicit-str-concat
145
+ "LOG", # flake8-logging
146
+ "N", # pep8-naming
147
+ "PERF", # Perflint
148
+ "PGH", # pygrep-hooks
149
+ "PIE", # flake8-pie
150
+ "PLC", # pylint-convention
151
+ "PLE", # pylint-error
152
+ "PLR", # pylint-refactor
153
+ "PLW", # pylint-warning
154
+ "PT", # flake8-pytest-style
155
+ "PTH", # flake8-use-pathlib
156
+ "PYI", # flake8-pyi
157
+ "Q", # flake8-quotes
158
+ "RET", # flake8-return
159
+ "RSE", # flake8-raise
160
+ "RUF", # ruff-specific
161
+ "S", # flake8-bandit
162
+ "SIM", # flake8-simplify
163
+ "SLF", # flake8-self
164
+ "T10", # flake8-debugger
165
+ "T20", # flake8-print
166
+ "TCH", # flake8-type-checking
167
+ "TID", # flake8-tidy-imports
168
+ "UP", # pyupgrade
169
+ "W", # pycodestyle
170
+ "YTT", # flake8-2020
171
+ ]
172
+
173
+ [tool.ruff.lint.pydocstyle]
174
+ convention = "pep257"
175
+
176
+ [tool.ruff.lint.per-file-ignores]
177
+ "__init__.py" = ["F401"]
178
+ "tests/**" = [
179
+ "D103", # undocumented-public-function
180
+ "PLR2004", # magic-value-comparison
181
+ "S101", # assert
182
+ "SLF001", # private-member-access
183
+ # INP001 wants an `__init__.py` here. Adding one would make `tests` a
184
+ # package, which changes how pytest imports these modules and breaks the
185
+ # `sys.path` insertion in `conftest.py` that makes the extension fixture
186
+ # importable the way an installed extension would be. The rule exists to
187
+ # catch source accidentally left as a namespace package; a pytest test
188
+ # directory is not that.
189
+ "INP001",
190
+ ]
191
+
192
+ # Three deviations, each specific to this codebase rather than to taste.
193
+ #
194
+ # T201 in the CLI: a command-line tool's output *is* `print`. Routing it
195
+ # through a logger to satisfy the rule would make the thing worse at its job.
196
+ "src/varda/cli.py" = ["T201"]
197
+ #
198
+ # D102 in the model layer: `model.py` is mostly one-line property wrappers,
199
+ # and the only docstring they could carry is the property name restated. The
200
+ # class docstrings carry the meaning; the accessors do not need one each.
201
+ "src/varda/model.py" = ["D102"]
202
+ #
203
+ # D103 in the rules: every rule registers a human-readable title in its
204
+ # decorator, and `varda rules` prints it. A docstring is reserved for rules
205
+ # whose *reasoning* is not obvious, and `varda rules -v` prints those.
206
+ # Requiring one on all twenty-one would duplicate the title twenty-one times.
207
+ "src/varda/rules.py" = ["D103"]
208
+ #
209
+ # scripts/ is build tooling, not an importable package — INP001 wants an
210
+ # __init__.py that would serve no purpose. T201 because writing to stdout is
211
+ # how a build script reports what it wrote.
212
+ "scripts/**" = ["INP001", "T201"]
varda-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,29 @@
1
+ """Varda — dimensional modeling for LinkML.
2
+
3
+ A profile of LinkML that adds the vocabulary of dimensional modeling — facts,
4
+ dimensions, grain, additivity, slowly-changing dimensions — plus the rules
5
+ that check a model against it and the generators that build from it.
6
+
7
+ Third parties import :mod:`varda.ext` and nothing else. Everything reachable
8
+ from there is public and versioned; everything else is internal and moves
9
+ without notice.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ __version__ = "0.1.0"
15
+
16
+ from .ext import Context, Extension, ExtensionError, Generator
17
+ from .model import DimensionalModel
18
+ from .rules import Finding, RuleSet
19
+
20
+ __all__ = [
21
+ "Context",
22
+ "DimensionalModel",
23
+ "Extension",
24
+ "ExtensionError",
25
+ "Finding",
26
+ "Generator",
27
+ "RuleSet",
28
+ "__version__",
29
+ ]
@@ -0,0 +1,8 @@
1
+ """Allow ``python -m varda``."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from .cli import main
6
+
7
+ if __name__ == "__main__":
8
+ raise SystemExit(main())