hklpy2-solvers 0.1.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.
@@ -0,0 +1,11 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "github-actions"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+
8
+ - package-ecosystem: "pip"
9
+ directory: "/"
10
+ schedule:
11
+ interval: "weekly"
@@ -0,0 +1,38 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
16
+
17
+ steps:
18
+ - uses: actions/checkout@v6
19
+
20
+ - name: Set up Python ${{ matrix.python-version }}
21
+ uses: actions/setup-python@v6
22
+ with:
23
+ python-version: ${{ matrix.python-version }}
24
+
25
+ - name: Install package with dev dependencies
26
+ run: pip install -e ".[dev]"
27
+
28
+ - name: Lint with ruff
29
+ run: ruff check .
30
+
31
+ - name: Check formatting with ruff
32
+ run: ruff format --check .
33
+
34
+ - name: Run tests with coverage
35
+ run: |
36
+ coverage run --source=hklpy2_solvers --concurrency=thread --parallel-mode -m pytest -q
37
+ coverage combine
38
+ coverage report --precision 3 -m
@@ -0,0 +1,51 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ tags: ["v*"]
7
+
8
+ permissions:
9
+ id-token: write
10
+
11
+ jobs:
12
+ build:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v6
16
+ with:
17
+ fetch-depth: 0 # full history for setuptools-scm
18
+
19
+ - name: Set up Python
20
+ uses: actions/setup-python@v6
21
+ with:
22
+ python-version: "3.12"
23
+
24
+ - name: Install build tools
25
+ run: pip install build
26
+
27
+ - name: Build package
28
+ run: python -m build
29
+
30
+ - name: Upload dist artifacts
31
+ uses: actions/upload-artifact@v7
32
+ with:
33
+ name: dist
34
+ path: dist/
35
+
36
+ publish:
37
+ if: startsWith(github.ref, 'refs/tags/v')
38
+ needs: build
39
+ runs-on: ubuntu-latest
40
+ environment: pypi
41
+ permissions:
42
+ id-token: write
43
+ steps:
44
+ - name: Download dist artifacts
45
+ uses: actions/download-artifact@v8
46
+ with:
47
+ name: dist
48
+ path: dist/
49
+
50
+ - name: Publish to PyPI
51
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,106 @@
1
+ # custom for GitHub Actions workflow
2
+ conda_env.yml
3
+ pip_req.txt
4
+
5
+ # Byte-compiled / optimized / DLL files
6
+ __pycache__/
7
+ *.py[cod]
8
+
9
+ # C extensions
10
+ *.so
11
+
12
+ # Distribution / packaging
13
+ .Python
14
+ env/
15
+ build/
16
+ develop-eggs/
17
+ dist/
18
+ downloads/
19
+ eggs/
20
+ lib/
21
+ lib64/
22
+ parts/
23
+ sdist/
24
+ var/
25
+ *.egg-info/
26
+ .installed.cfg
27
+ *.egg
28
+
29
+ # PyInstaller
30
+ *.manifest
31
+ *.spec
32
+
33
+ # Installer logs
34
+ pip-log.txt
35
+ pip-delete-this-directory.txt
36
+
37
+ # Unit test / coverage reports
38
+ htmlcov/
39
+ .tox/
40
+ .coverage*
41
+ .cache
42
+ nosetests.xml
43
+ coverage.xml
44
+
45
+ # Translations
46
+ *.mo
47
+ *.pot
48
+
49
+ # Django stuff:
50
+ *.log
51
+
52
+ # Sphinx documentation
53
+ docs/_build/
54
+ docs/source/_build/
55
+ docs/source/autoapi
56
+
57
+ # PyBuilder
58
+ target/
59
+
60
+ # Original file
61
+ *.pyc
62
+ *.swp
63
+ *.bak
64
+
65
+ # PyCharm
66
+ .idea/
67
+ .ropeproject
68
+
69
+ # notebook checkpoints
70
+ .ipynb_checkpoints
71
+
72
+ # Microsoft VS Code editor
73
+ .vscode/
74
+ .history/
75
+
76
+ # PyTest cache
77
+ .pytest_cache/
78
+
79
+ # Virtual environments
80
+ .venv/
81
+ venv/
82
+
83
+ # Bluesky session logger
84
+ .logs/
85
+
86
+ # local developer files
87
+ dev_*
88
+ .dev/
89
+
90
+ # RE.md saved by local bluesky session
91
+ .re_md_dict.yml
92
+
93
+ # EPICS softIoc
94
+ .iocsh_history
95
+
96
+ # Droppings by our IT group
97
+ .loglogin
98
+
99
+ # Claude
100
+ .claude/
101
+
102
+ # hatch-vcs generated version file
103
+ src/hklpy2_solvers/_version.py
104
+
105
+ # ruff cache
106
+ .ruff_cache/
@@ -0,0 +1,27 @@
1
+ # hint: pre-commit run --all-files
2
+
3
+ default_language_version:
4
+ python: python3.13
5
+
6
+ repos:
7
+ - repo: https://github.com/pre-commit/pre-commit-hooks
8
+ rev: v6.0.0
9
+ hooks:
10
+ - id: check-yaml
11
+ - id: check-toml
12
+ - id: check-ast
13
+ - id: check-merge-conflict
14
+ - id: check-added-large-files
15
+ args: ["--maxkb=2000"]
16
+ - id: mixed-line-ending
17
+ - id: end-of-file-fixer
18
+ - id: trailing-whitespace
19
+ - id: check-case-conflict
20
+ - id: check-executables-have-shebangs
21
+ - repo: https://github.com/astral-sh/ruff-pre-commit
22
+ rev: v0.15.6
23
+ hooks:
24
+ - id: ruff # replaces Flake8, isort, pydocstyle, pyupgrade
25
+ args:
26
+ - --fix
27
+ - id: ruff-format # replaces Black
@@ -0,0 +1,312 @@
1
+ # AI Agent advice for hklpy2_solvers
2
+
3
+ <https://agents.md>
4
+
5
+ ## Purpose
6
+
7
+ Goal: Short guide for coding agents (auto-formatters, linters, CI bots, test runners, codegen agents) working on this Python project.
8
+
9
+ ## Code Style
10
+
11
+ - Concise type annotations
12
+ - code location described in pyproject.toml
13
+ - style information described in pyproject.toml
14
+ - `pre-commit run --all-files`
15
+
16
+
17
+ ## Agent pytest style (for automated agents) - MANDATORY
18
+
19
+ ---
20
+
21
+ **CRITICAL: All test code MUST follow this pattern. Tests not following this pattern will be rejected.**
22
+
23
+ ### Requirements
24
+
25
+ 1. **ALWAYS use parametrized pytest** with `parms, context` as the parameter names
26
+ 2. **ALWAYS use `pytest.param()`** for each parameter set with `id="..."`
27
+ 3. **ALWAYS use context managers**: `does_not_raise()` for success, `pytest.raises(...)` for failures
28
+ 4. **ALWAYS put all functional code and assertions inside `with context:` block**
29
+ 5. **ALWAYS use `match=re.escape(...)` with `pytest.raises(...)`** for exception matching
30
+ 6. **ALWAYS include failure test cases** - parameter sets that are expected to raise exceptions must use `pytest.raises(...)`
31
+ 7. **NEVER create separate test functions** for success vs failure cases
32
+ 8. **NEVER use try/except** for test logic
33
+ 9. **NEVER use the deprecated `assert_context_result()` helper**
34
+
35
+ ### Import requirements
36
+
37
+ ```python
38
+ from contextlib import nullcontext as does_not_raise
39
+ import pytest
40
+ ```
41
+
42
+ ### Correct pattern (copy this exactly):
43
+
44
+ ```py
45
+ @pytest.mark.parametrize(
46
+ "parms, context",
47
+ [
48
+ pytest.param(
49
+ dict(some_param=value1),
50
+ does_not_raise(),
51
+ id="description of test case 1",
52
+ ),
53
+ pytest.param(
54
+ dict(some_param=invalid_value),
55
+ pytest.raises(SomeError, match=re.escape("expected message")),
56
+ id="description of test case 2",
57
+ ),
58
+ ],
59
+ )
60
+ def test_function_name(parms, context):
61
+ with context:
62
+ # ALL code that might raise goes HERE
63
+ result = object_under_test.method(**parms)
64
+ # ALL assertions go HERE (inside the with block)
65
+ assert result.expected_attribute == some_value
66
+ ```
67
+
68
+ ### Common mistakes to avoid
69
+
70
+ - NOT this:
71
+ ```py
72
+ def test_something():
73
+ # setup code...
74
+ # test code...
75
+ ```
76
+
77
+ - NOT this:
78
+ ```py
79
+ def test_success_case():
80
+ # code...
81
+ assert result == expected
82
+
83
+ def test_failure_case():
84
+ with pytest.raises(...):
85
+ # code...
86
+ ```
87
+
88
+ - NOT this:
89
+ ```py
90
+ @pytest.mark.parametrize(...)
91
+ def test_something(values):
92
+ try:
93
+ result = do_something(values)
94
+ except SomeError:
95
+ # wrong!
96
+ ```
97
+
98
+ - ALWAYS this:
99
+ ```py
100
+ @pytest.mark.parametrize(
101
+ "parms, context",
102
+ [
103
+ pytest.param(dict(value=valid), does_not_raise(), id="valid case"),
104
+ pytest.param(dict(value=invalid), pytest.raises(Error), id="error case"),
105
+ ],
106
+ )
107
+ def test_something(parms, context):
108
+ with context:
109
+ result = do_something(**parms)
110
+ ```
111
+
112
+ ## Enforcement
113
+
114
+ PRs opened or modified by automated agents must follow the "Agent pytest style" described above. Reviewers and CI will check for this pattern (test parametrization and use of context managers for expected outcomes, both successful and failed). Changes from agents that do not comply may be requested for revision or reverted.
115
+
116
+ ## Agent behavior rules
117
+
118
+ - Always follow the project's formatting, linting, and typing configs.
119
+ - Make minimal, focused changes; prefer separate commits per concern.
120
+ - Add or update tests for any behavioral change.
121
+ - Include clear commit messages and PR descriptions.
122
+ - If uncertain about design, open an issue instead of making large changes.
123
+ - Respect branch protection: push to feature branches and create PRs.
124
+
125
+ ## Test style
126
+
127
+ - All test code for MODULE.py goes in file tests/test_MODULE.py
128
+ - tests should be written and organized using the project's test style guidelines.
129
+ - use parametrized pytests
130
+ - Prefer parameter sets that simulate user interactions
131
+ - all tests run code within context
132
+ - maximize code coverage
133
+ - Use parametrized pytests
134
+ - Generate additional parameters and sets to minimize the number of test functions.
135
+ - Place all functional code in a parametrized context.
136
+ - use parameter for does_not_raise() or pytest.raises(...) as fits the parameter set
137
+ - `from contextlib import nullcontext as does_not_raise`
138
+ - do not separate success and errors tests into different test functions
139
+ - do not separate success and errors tests using try..except
140
+
141
+ ## Inputs & outputs
142
+
143
+ - Inputs: file diffs, test results, config files, repository metadata
144
+ - Outputs: patch/commit, tests, updated docs, CI status
145
+
146
+ ## Running locally
147
+
148
+ - Setup: create virtualenv, `pip install -e .[all]`
149
+ - Common commands:
150
+ - Format & Lint: `make style` or `pre-commit run --all-files`
151
+ - Test: `pytest ./src`
152
+
153
+ ### pre-commit on NFS home directories
154
+
155
+ The pre-commit cache (`~/.cache/pre-commit`) lives on NFS on this system
156
+ (`aquila:/export/beams1`). Setuptools' wheel-build cleanup uses `os.rmdir()`
157
+ which fails non-deterministically on NFS because directory-entry removals are
158
+ not immediately visible. Symptom: `[Errno 39] Directory not empty` during
159
+ `pip install` for any pre-commit hook environment.
160
+
161
+ **Fix:** keep the pre-commit cache on local disk:
162
+
163
+ ```bash
164
+ export PRE_COMMIT_HOME=/tmp/pre-commit-JEMIAN # in ~/.bashrc and ~/.profile
165
+ ```
166
+
167
+ This is already set in `~/.bashrc`, `~/.profile`, and hardcoded in
168
+ `.git/hooks/pre-commit` (between the `# end templated` line and the `HERE=`
169
+ line). If `pre-commit install` regenerates the hook, re-add that line:
170
+
171
+ ```bash
172
+ # Use local disk for pre-commit cache (avoids NFS rmdir failures)
173
+ export PRE_COMMIT_HOME=/tmp/pre-commit-JEMIAN
174
+ ```
175
+
176
+ The `Makefile` `pre` target also exports this variable automatically.
177
+
178
+ ## CI integration
179
+
180
+ - Format and lint in pre-commit job
181
+ - Run tests and dependency audit on PRs.
182
+
183
+ ## Minimal example PR checklist
184
+
185
+ - Runs formatting and linting locally
186
+ - Adds/updates tests for changes
187
+ - Updates `RELEASE_NOTES.rst` under the current development heading
188
+ - Marks PR as draft if large refactor
189
+
190
+ ## Release Notes
191
+
192
+ - Update `RELEASE_NOTES.rst` as part of every PR that introduces a new
193
+ feature, fix, enhancement, or maintenance change.
194
+ - Add the entry under the current development version heading (the topmost
195
+ unreleased section inside the ``.. comment`` block).
196
+ - Entries should be terse — one or two lines — and reference the issue or PR
197
+ number with ``:issue:`N``` or ``:pr:`N```.
198
+ - Use the appropriate subsection and keep subsections in the logical order
199
+ defined at the top of ``RELEASE_NOTES.rst``: Notice, Breaking Changes, New
200
+ Features, Enhancements, Fixes, Maintenance, Deprecations, New Contributors.
201
+ - Sort entries alphabetically within each subsection.
202
+
203
+ ## Git Issues, Branches, Commits, and Pull Requests
204
+
205
+ All non-trivial work follows this lifecycle: **Issue -> Branch -> Commits ->
206
+ Pull Request**. Each step is described below with the concrete rules agents
207
+ must follow.
208
+
209
+ ### Issues
210
+
211
+ Every piece of work starts with an issue. Issues answer the most expensive
212
+ question in code maintenance: *Why is this change being made?*
213
+
214
+ - An issue describes the observation, bug, feature request, or maintenance
215
+ task that motivates the work.
216
+ - Do not begin coding without a corresponding issue (the only exception is a
217
+ truly trivial fix that needs no explanation).
218
+
219
+ ### Branches
220
+
221
+ All development happens on feature branches, never directly on `main`.
222
+
223
+ - **Naming convention**: `<ISSUE_NUMBER>-<CONCISE-TITLE>`
224
+ - The concise title is derived from the issue title, using lowercase words
225
+ separated by hyphens.
226
+ - Example: for issue #42 titled "Add timeout to LDAP queries", the branch
227
+ name is `42-add-ldap-timeout`.
228
+ - Create the branch from the current `main`:
229
+ `git checkout -b <branch-name> main`
230
+ - Push with tracking: `git push -u origin <branch-name>`
231
+
232
+ ### Commits
233
+
234
+ Write commit messages following the
235
+ [Conventional Commits](https://www.conventionalcommits.org/) style with the
236
+ issue number included.
237
+
238
+ **Format:**
239
+
240
+ ```text
241
+ <PREFIX> #<ISSUE_NUMBER> concise subject line
242
+
243
+ Optional body with additional context.
244
+ Agent: <agent name> (<model name>)
245
+ ```
246
+
247
+ **Prefix values** (use the one that best describes the change):
248
+
249
+ | Prefix | Use for |
250
+ |--------|---------|
251
+ | `feat` | New feature or capability |
252
+ | `fix` | Bug fix |
253
+ | `docs` | Documentation only |
254
+ | `refactor` | Code restructuring, no behavior change |
255
+ | `style` | Formatting, linting, whitespace |
256
+ | `maint` | Maintenance, dependency updates, housekeeping |
257
+ | `ci` | CI/CD configuration |
258
+ | `test` | Adding or updating tests |
259
+
260
+ **Examples:**
261
+
262
+ ```text
263
+ feat #42 add configurable timeout to LDAP queries
264
+
265
+ Default timeout is 30 s; configurable via dm_config.ini.
266
+ Agent: OpenCode (claudesonnet46)
267
+ ```
268
+
269
+ ```text
270
+ docs #15 update AGENTS.md with branching workflow
271
+ ```
272
+
273
+ ### Pull Requests
274
+
275
+ A Pull Request (PR) describes *how* an issue has been (or will be) addressed.
276
+
277
+ - Every PR **must** reference at least one issue.
278
+ - The PR body **must** include a `closes #N` directive for the issue it
279
+ resolves. Use a bullet list at the top of the PR body:
280
+
281
+ ```md
282
+ - closes #42
283
+ - #15
284
+ ```
285
+
286
+ Using `closes #N` will auto-close the issue when the PR is merged.
287
+ - The PR title should be a concise summary of the change.
288
+ - Assign the PR to the user running the agent (determine with ``gh api user --jq '.login'``).
289
+ - Copy the issue's labels, project(s), milestone, and status to the PR.
290
+ - Sign the PR body with the agent and model name:
291
+
292
+ ```md
293
+ Agent: OpenCode (claudesonnet46)
294
+ ```
295
+
296
+ - PR discussion comments should explain the approach, trade-offs, and any
297
+ open questions.
298
+ - Sign all PR and issue comments with the agent and model name:
299
+
300
+ ```md
301
+ Agent: OpenCode (claudesonnet46)
302
+ ```
303
+
304
+ ## Notes
305
+
306
+ - Keep agent actions small, reversible, and reviewable.
307
+ - When updating a file, verify that a change has actually been made by comparing
308
+ the mtime before and after the edits.
309
+
310
+ ## Code Coverage
311
+
312
+ - Aim for 100% coverage, but prioritize meaningful tests over simply hitting every line.
@@ -0,0 +1,48 @@
1
+ Copyright (c) 2025-2026, UChicago Argonne, LLC
2
+
3
+ All Rights Reserved
4
+
5
+ hklpy2_solvers
6
+
7
+ BCDA, Advanced Photon Source, Argonne National Laboratory
8
+
9
+
10
+ OPEN SOURCE LICENSE
11
+
12
+ Redistribution and use in source and binary forms, with or without
13
+ modification, are permitted provided that the following conditions are met:
14
+
15
+ 1. Redistributions of source code must retain the above copyright notice,
16
+ this list of conditions and the following disclaimer. Software changes,
17
+ modifications, or derivative works, should be noted with comments and
18
+ the author and organization's name.
19
+
20
+ 2. Redistributions in binary form must reproduce the above copyright notice,
21
+ this list of conditions and the following disclaimer in the documentation
22
+ and/or other materials provided with the distribution.
23
+
24
+ 3. Neither the names of UChicago Argonne, LLC or the Department of Energy
25
+ nor the names of its contributors may be used to endorse or promote
26
+ products derived from this software without specific prior written
27
+ permission.
28
+
29
+ 4. The software and the end-user documentation included with the
30
+ redistribution, if any, must include the following acknowledgment:
31
+
32
+ "This product includes software produced by UChicago Argonne, LLC
33
+ under Contract No. DE-AC02-06CH11357 with the Department of Energy."
34
+
35
+ ****************************************************************************
36
+
37
+ DISCLAIMER
38
+
39
+ THE SOFTWARE IS SUPPLIED "AS IS" WITHOUT WARRANTY OF ANY KIND.
40
+
41
+ Neither the United States GOVERNMENT, nor the United States Department
42
+ of Energy, NOR uchicago argonne, LLC, nor any of their employees, makes
43
+ any warranty, express or implied, or assumes any legal liability or
44
+ responsibility for the accuracy, completeness, or usefulness of any
45
+ information, data, apparatus, product, or process disclosed, or
46
+ represents that its use would not infer privately owned rights.
47
+
48
+ ****************************************************************************
@@ -0,0 +1,25 @@
1
+ # Makefile to support common developer commands
2
+
3
+ # Keep pre-commit cache on local disk (avoids NFS rmdir failures on this system).
4
+ # See AGENTS.md "pre-commit on NFS home directories" for details.
5
+ export PRE_COMMIT_HOME := /tmp/pre-commit-JEMIAN
6
+
7
+ all :: style coverage
8
+
9
+ coverage:
10
+ coverage run --concurrency=thread --parallel-mode -m pytest -q ./src
11
+ coverage combine
12
+ coverage report --precision 3 -m
13
+ coverage html
14
+
15
+ isort:
16
+ isort --sl ./src
17
+
18
+ pre:
19
+ pre-commit run --all-files
20
+ ruff check .
21
+
22
+ style :: isort pre
23
+
24
+ test:
25
+ pytest -q --lf ./src
@@ -0,0 +1,77 @@
1
+ Metadata-Version: 2.4
2
+ Name: hklpy2-solvers
3
+ Version: 0.1.4
4
+ Summary: Solvers for the hklpy2 package
5
+ Project-URL: homepage, https://github.com/prjemian/hklpy2_solvers
6
+ Project-URL: issues, https://github.com/prjemian/hklpy2_solvers/issues
7
+ Project-URL: source, https://github.com/prjemian/hklpy2_solvers
8
+ Author-email: Pete Jemian <prjemian+hklpy2@gmail.com>
9
+ Maintainer-email: Pete Jemian <prjemian+hklpy2@gmail.com>
10
+ License-Expression: LicenseRef-UChicago-Argonne-LLC-License
11
+ License-File: LICENSE
12
+ Keywords: bluesky,diffraction,diffractometer,hklpy2,solver
13
+ Classifier: Development Status :: 2 - Pre-Alpha
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Topic :: Scientific/Engineering
20
+ Requires-Python: >=3.10
21
+ Requires-Dist: diffcalc-core
22
+ Requires-Dist: hklpy2
23
+ Requires-Dist: numpy
24
+ Provides-Extra: all
25
+ Requires-Dist: build; extra == 'all'
26
+ Requires-Dist: coverage; extra == 'all'
27
+ Requires-Dist: isort; extra == 'all'
28
+ Requires-Dist: pre-commit; extra == 'all'
29
+ Requires-Dist: pytest; extra == 'all'
30
+ Requires-Dist: pytest-cov; extra == 'all'
31
+ Requires-Dist: ruff; extra == 'all'
32
+ Provides-Extra: dev
33
+ Requires-Dist: build; extra == 'dev'
34
+ Requires-Dist: coverage; extra == 'dev'
35
+ Requires-Dist: isort; extra == 'dev'
36
+ Requires-Dist: pre-commit; extra == 'dev'
37
+ Requires-Dist: pytest; extra == 'dev'
38
+ Requires-Dist: pytest-cov; extra == 'dev'
39
+ Requires-Dist: ruff; extra == 'dev'
40
+ Description-Content-Type: text/markdown
41
+
42
+ # hklpy2_solvers
43
+
44
+ [![PyPI](https://img.shields.io/pypi/v/hklpy2-solvers.svg)](https://pypi.org/project/hklpy2-solvers)
45
+ [![License](https://img.shields.io/pypi/l/hklpy2-solvers.svg)](https://github.com/prjemian/hklpy2_solvers/blob/main/LICENSE)
46
+
47
+ Solvers for the [hklpy2](https://github.com/prjemian/hklpy2) package.
48
+
49
+ ## Solvers
50
+
51
+ | Solver | Library | Geometry | Description |
52
+ | --- | --- | --- | --- |
53
+ | `diffcalc` | [diffcalc-core](https://github.com/DiamondLightSource/diffcalc-core) | 4S+2D six-circle | You (1999) six-circle diffractometer (mu, delta, nu, eta, chi, phi) |
54
+
55
+ ## Installation
56
+
57
+ ```bash
58
+ pip install hklpy2-solvers
59
+ ```
60
+
61
+ ## Development
62
+
63
+ ```bash
64
+ git clone https://github.com/prjemian/hklpy2_solvers
65
+ cd hklpy2_solvers
66
+ pip install -e ".[dev]"
67
+ pytest
68
+ ```
69
+
70
+ ## Versioning
71
+
72
+ Versions are derived automatically from git tags using [hatch-vcs](https://github.com/ofek/hatch-vcs).
73
+ To release a new version, create an annotated git tag:
74
+
75
+ ```bash
76
+ git tag -a v0.1.0 -m "Release v0.1.0"
77
+ ```