nc-gcode-interpreter 0.2.6__tar.gz → 0.2.7__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.
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/.github/workflows/build-and-release.yml +3 -1
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/CHANGELOG.md +27 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/Cargo.lock +1 -1
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/Cargo.toml +1 -1
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/Development.md +27 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/PKG-INFO +1 -1
- nc_gcode_interpreter-0.2.7/build.rs +62 -0
- nc_gcode_interpreter-0.2.7/build_backend/nc_build_backend.py +116 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/ggroups/generate_g_commands.py +2 -2
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/pyproject.toml +24 -1
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/nc_gcode_interpreter/__init__.py +27 -21
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/nc_gcode_interpreter/_internal.pyi +18 -19
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/nc_gcode_interpreter/cli.py +2 -1
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/nc_gcode_interpreter/viz.py +1 -1
- nc_gcode_interpreter-0.2.7/python/tests/nc_source.py +11 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/tests/test_batch_variables.py +42 -53
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/tests/test_batches.py +5 -5
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/tests/test_diagnostics.py +1 -1
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/tests/test_expected_output.py +3 -2
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/tests/test_field_defects.py +0 -1
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/tests/test_flags.py +1 -1
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/tests/test_flatten.py +8 -2
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/tests/test_jumps.py +42 -51
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/tests/test_streaming.py +29 -36
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/src/main.rs +1 -1
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/.gitignore +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/CONTRIBUTING.md +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/LICENSE +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/README.md +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/TODO.md +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/docs/resumable-interpretation-design.md +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/docs/sinumerik-execution-model.md +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/actual_position.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/actual_position.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/arc.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/arc.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/arrays.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/arrays.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/axis_index_assignment.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/axis_index_assignment.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/basic_math.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/basic_math.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/case.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/case.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/case_insensitive_variables.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/case_insensitive_variables.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/custom_vars.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/custom_vars.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/def_string.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/def_string.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/defaults.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/defaults.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/edge_cases.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/edge_cases.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/flattening/flatten_demo.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/flattening/flatten_demo_flattened.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/flattening/flatten_demo_raw.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/for_loop.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/for_loop.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/function_calls.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/function_calls.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/goto.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/goto.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/if_statement.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/if_statement.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/increment.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/increment.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/logic_operators.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/logic_operators.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/loop.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/loop.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/multiple_m_codes.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/multiple_m_codes.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/precedence.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/precedence.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/r_param.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/r_param.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/repeat.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/repeat.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/simple.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/simple.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/spline.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/spline.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/tool.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/tool.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/trans.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/trans.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/trans2.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/trans2.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/trans_ic.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/trans_ic.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/trans_reset.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/trans_reset.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/trig.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/trig.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/variables.csv +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/examples/variables.mpf +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/example/minimal.py +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/example/streaming.py +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/nc_gcode_interpreter/ggroups.json +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/nc_gcode_interpreter/py.typed +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/tests/test_arithmetic_functions.py +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/tests/test_g_groups.py +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/tests/test_g_vocabulary.py +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/tests/test_real_comparisons.py +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/tests/test_stage1.py +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/tests/test_string_operations.py +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/tests/test_structured_errors.py +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/tests/test_unsupported.py +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/rustfmt.toml +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/src/errors.rs +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/src/flatten.rs +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/src/grammar.pest +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/src/interpret_rules.rs +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/src/interpreter.rs +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/src/lib.rs +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/src/line_driver.rs +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/src/modal_groups.rs +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/src/output.rs +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/src/state.rs +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/src/structure_scan.rs +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/src/types.rs +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/src/vm.rs +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/tests/cli.rs +0 -0
- {nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/uv.lock +0 -0
{nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/.github/workflows/build-and-release.yml
RENAMED
|
@@ -35,7 +35,9 @@ jobs:
|
|
|
35
35
|
with:
|
|
36
36
|
python-version: 3.13
|
|
37
37
|
- name: Install Python linter
|
|
38
|
-
|
|
38
|
+
# Pinned: an unpinned ruff silently widens its rule set on upgrade and
|
|
39
|
+
# turns the job red on code nobody touched. Bump deliberately.
|
|
40
|
+
run: pip install ruff==0.16.6
|
|
39
41
|
- name: Lint Python code with ruff
|
|
40
42
|
run: ruff check .
|
|
41
43
|
|
|
@@ -4,6 +4,33 @@ Notable changes to **nc-gcode-interpreter**. The format loosely follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/); versions are git tags,
|
|
5
5
|
released to PyPI.
|
|
6
6
|
|
|
7
|
+
## [v0.2.7] - 2026-09-08
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Local and editable builds now derive their version from `git describe`
|
|
12
|
+
instead of reporting the `0.0.0.dev0` placeholder: an editable checkout three
|
|
13
|
+
commits past `v0.2.6` reports `0.2.6.dev3+<sha>`. A small in-tree PEP 517
|
|
14
|
+
backend (`build_backend/nc_build_backend.py`) stamps the version onto the
|
|
15
|
+
`Cargo.toml` placeholder and hands off to maturin; the release CI, which
|
|
16
|
+
already writes the tag version into `Cargo.toml`, is untouched. Downstream
|
|
17
|
+
consumers installing this package editable now get a real version to pin
|
|
18
|
+
against and a signal that they are running a local edit (#65).
|
|
19
|
+
- `nc-gcode-interpreter --version` now reports the actual build version. It was
|
|
20
|
+
a hard-coded `1.0` string literal that had never matched any release; a
|
|
21
|
+
`build.rs` now derives the same `git describe` version for plain `cargo`
|
|
22
|
+
builds (which don't go through the PEP 517 shim) and the CLI reads it, so a
|
|
23
|
+
dev build prints e.g. `0.2.6-dev.1+ge5f2306` and a release build prints the
|
|
24
|
+
tag.
|
|
25
|
+
- Ruff's implicit default rule set widened in 0.16 and turned the lint job red
|
|
26
|
+
on 64 findings in untouched code. Pin the rule selection in `pyproject.toml`
|
|
27
|
+
and the ruff version in CI, so a linter upgrade adds rules only when asked,
|
|
28
|
+
and fix the findings. Mostly mechanical (`X | None`, `list`/`dict` builtins,
|
|
29
|
+
import sorting, explicit `zip(strict=)`). The rule set carries no `ignore`
|
|
30
|
+
list: the one rule that would have needed an exception, `FLY002`, is instead
|
|
31
|
+
satisfied by an `nc_lines(*blocks)` test helper, which keeps the NC test
|
|
32
|
+
programs one block per line with their explanatory comments intact.
|
|
33
|
+
|
|
7
34
|
## [v0.2.6] - 2026-07-09
|
|
8
35
|
|
|
9
36
|
### Added
|
|
@@ -30,6 +30,33 @@ cargo build --release
|
|
|
30
30
|
maturin develop --release --uv
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
+
### Versioning
|
|
34
|
+
|
|
35
|
+
`Cargo.toml` holds the placeholder version `0.0.0-dev`; the release workflow
|
|
36
|
+
rewrites it from the git tag before building the wheels, so the released
|
|
37
|
+
version always comes from the tag and never from a committed number.
|
|
38
|
+
|
|
39
|
+
Local builds get a version too. `build_backend/nc_build_backend.py` is an
|
|
40
|
+
in-tree PEP 517 backend that wraps maturin: when it sees the placeholder and
|
|
41
|
+
finds a git checkout with tags, it stamps
|
|
42
|
+
`git describe --tags --long --dirty` onto the `Cargo.toml` version as
|
|
43
|
+
`0.2.6-dev.3+g<sha>` (maturin normalises that to the PEP 440
|
|
44
|
+
`0.2.6.dev3+<sha>`), builds, then restores `Cargo.toml` and `Cargo.lock`. So an
|
|
45
|
+
editable `uv sync` reports the commit it was built from rather than
|
|
46
|
+
`0.0.0.dev0` - which is what lets a downstream consumer notice it is running a
|
|
47
|
+
local edit of the interpreter rather than a release.
|
|
48
|
+
|
|
49
|
+
Any non-placeholder version in `Cargo.toml` is left alone, so the CI release
|
|
50
|
+
path is unaffected. Without git (an unpacked sdist, say) the placeholder
|
|
51
|
+
stands.
|
|
52
|
+
|
|
53
|
+
A plain `cargo build` doesn't go through that shim, so `build.rs` derives the
|
|
54
|
+
same version independently and exposes it as `NC_GCODE_INTERPRETER_VERSION`,
|
|
55
|
+
which is what the CLI's `--version` reports. It applies the same rules: an
|
|
56
|
+
already-stamped `Cargo.toml` version wins, and without git the placeholder
|
|
57
|
+
stands. The CLI therefore shows cargo's semver spelling
|
|
58
|
+
(`0.2.6-dev.1+ge5f2306`), not maturin's PEP 440 normalisation of it.
|
|
59
|
+
|
|
33
60
|
### Release profile
|
|
34
61
|
|
|
35
62
|
`[profile.release]` currently sets no `strip`/`lto` overrides. `strip = true` was
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
//! Give `nc-gcode-interpreter --version` a real version in local builds.
|
|
2
|
+
//!
|
|
3
|
+
//! `Cargo.toml` carries the placeholder version `0.0.0-dev`, which the release
|
|
4
|
+
//! CI rewrites from the git tag. A plain `cargo build` in a checkout doesn't go
|
|
5
|
+
//! through the PEP 517 shim in `build_backend/` that does the same for wheels,
|
|
6
|
+
//! so without this the CLI would report `0.0.0-dev` for every dev build. Derive
|
|
7
|
+
//! the same `git describe`-based version here and expose it as
|
|
8
|
+
//! `NC_GCODE_INTERPRETER_VERSION`; fall back to the `Cargo.toml` version when
|
|
9
|
+
//! there is no git checkout (an unpacked sdist) or the version is already
|
|
10
|
+
//! stamped.
|
|
11
|
+
|
|
12
|
+
use std::process::Command;
|
|
13
|
+
|
|
14
|
+
const PLACEHOLDER: &str = "0.0.0-dev";
|
|
15
|
+
|
|
16
|
+
fn main() {
|
|
17
|
+
// Re-derive when the checkout moves: HEAD (branch switch), the index
|
|
18
|
+
// (commits, staging) and the tags. A bare unstaged edit won't retrigger
|
|
19
|
+
// the build script, so a stale `.dirty` suffix is possible; it clears on
|
|
20
|
+
// the next `cargo build` that recompiles anything.
|
|
21
|
+
println!("cargo:rerun-if-changed=.git/HEAD");
|
|
22
|
+
println!("cargo:rerun-if-changed=.git/index");
|
|
23
|
+
println!("cargo:rerun-if-changed=.git/refs/tags");
|
|
24
|
+
|
|
25
|
+
let cargo_version = env!("CARGO_PKG_VERSION");
|
|
26
|
+
let version = if cargo_version == PLACEHOLDER {
|
|
27
|
+
git_version().unwrap_or_else(|| cargo_version.to_string())
|
|
28
|
+
} else {
|
|
29
|
+
cargo_version.to_string()
|
|
30
|
+
};
|
|
31
|
+
println!("cargo:rustc-env=NC_GCODE_INTERPRETER_VERSION={version}");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/// `v0.2.6-3-g1234abc[-dirty]` -> `0.2.6-dev.3+g1234abc[.dirty]`, or the bare
|
|
35
|
+
/// tag when we are exactly on a clean tag.
|
|
36
|
+
fn git_version() -> Option<String> {
|
|
37
|
+
let output = Command::new("git")
|
|
38
|
+
.args(["describe", "--tags", "--long", "--dirty", "--match", "v[0-9]*"])
|
|
39
|
+
.output()
|
|
40
|
+
.ok()?;
|
|
41
|
+
if !output.status.success() {
|
|
42
|
+
return None;
|
|
43
|
+
}
|
|
44
|
+
let described = String::from_utf8(output.stdout).ok()?;
|
|
45
|
+
let described = described.trim().strip_prefix('v')?;
|
|
46
|
+
|
|
47
|
+
let (described, dirty) = match described.strip_suffix("-dirty") {
|
|
48
|
+
Some(rest) => (rest, true),
|
|
49
|
+
None => (described, false),
|
|
50
|
+
};
|
|
51
|
+
// Split off the trailing `-<distance>-g<sha>`; the tag itself may contain
|
|
52
|
+
// `-`, so scan from the right.
|
|
53
|
+
let (rest, sha) = described.rsplit_once('-')?;
|
|
54
|
+
let (tag, distance) = rest.rsplit_once('-')?;
|
|
55
|
+
let distance: u32 = distance.parse().ok()?;
|
|
56
|
+
|
|
57
|
+
if distance == 0 && !dirty {
|
|
58
|
+
return Some(tag.to_string());
|
|
59
|
+
}
|
|
60
|
+
let local = if dirty { format!("{sha}.dirty") } else { sha.to_string() };
|
|
61
|
+
Some(format!("{tag}-dev.{distance}+{local}"))
|
|
62
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""In-tree PEP 517 backend: give local builds a version from the git tag.
|
|
2
|
+
|
|
3
|
+
`Cargo.toml` carries the placeholder version `0.0.0-dev`, which the release CI
|
|
4
|
+
rewrites from the tag before building. Without this shim every non-release
|
|
5
|
+
build -- notably an editable `uv sync` in a sibling checkout -- reports
|
|
6
|
+
`0.0.0.dev0`, which is useless as a version floor and gives a downstream
|
|
7
|
+
consumer no signal that its interpreter is a local edit rather than a release.
|
|
8
|
+
|
|
9
|
+
So: when the placeholder is still in place and we are inside a git checkout
|
|
10
|
+
with tags, rewrite it to a semver dev version derived from `git describe`
|
|
11
|
+
(`0.2.6-dev.3+g1234abc`), which maturin normalises to the PEP 440
|
|
12
|
+
`0.2.6.dev3+g1234abc`. Any other version in `Cargo.toml` is left alone, so the
|
|
13
|
+
CI release path is untouched.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import re
|
|
19
|
+
import subprocess
|
|
20
|
+
from contextlib import contextmanager
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
from maturin import build_editable as _maturin_build_editable
|
|
24
|
+
from maturin import build_sdist as _maturin_build_sdist
|
|
25
|
+
from maturin import build_wheel as _maturin_build_wheel
|
|
26
|
+
|
|
27
|
+
# The hooks this module does not wrap are re-exported unchanged; the rest are
|
|
28
|
+
# imported under an alias and overridden below.
|
|
29
|
+
from maturin import ( # noqa: F401
|
|
30
|
+
get_requires_for_build_editable,
|
|
31
|
+
get_requires_for_build_sdist,
|
|
32
|
+
get_requires_for_build_wheel,
|
|
33
|
+
)
|
|
34
|
+
from maturin import (
|
|
35
|
+
prepare_metadata_for_build_editable as _maturin_prepare_metadata_for_build_editable,
|
|
36
|
+
)
|
|
37
|
+
from maturin import (
|
|
38
|
+
prepare_metadata_for_build_wheel as _maturin_prepare_metadata_for_build_wheel,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
PLACEHOLDER = "0.0.0-dev"
|
|
42
|
+
_VERSION_LINE = re.compile(r'^version = ".*"$', re.MULTILINE)
|
|
43
|
+
# v0.2.6-3-g1234abc[-dirty]
|
|
44
|
+
_DESCRIBE = re.compile(r"^v(?P<tag>.+)-(?P<distance>\d+)-g(?P<sha>[0-9a-f]+)(?P<dirty>-dirty)?$")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _git_version(root: Path) -> str | None:
|
|
48
|
+
"""Semver dev version from `git describe`, or None if it can't be derived."""
|
|
49
|
+
try:
|
|
50
|
+
described = subprocess.run(
|
|
51
|
+
["git", "describe", "--tags", "--long", "--dirty", "--match", "v[0-9]*"],
|
|
52
|
+
cwd=root,
|
|
53
|
+
capture_output=True,
|
|
54
|
+
text=True,
|
|
55
|
+
check=True,
|
|
56
|
+
).stdout.strip()
|
|
57
|
+
except (OSError, subprocess.CalledProcessError):
|
|
58
|
+
return None
|
|
59
|
+
match = _DESCRIBE.match(described)
|
|
60
|
+
if not match:
|
|
61
|
+
return None
|
|
62
|
+
tag, distance, sha = match["tag"], int(match["distance"]), match["sha"]
|
|
63
|
+
if distance == 0 and not match["dirty"]:
|
|
64
|
+
return tag
|
|
65
|
+
local = sha if not match["dirty"] else f"{sha}.dirty"
|
|
66
|
+
return f"{tag}-dev.{distance}+{local}"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@contextmanager
|
|
70
|
+
def _versioned_cargo_toml():
|
|
71
|
+
root = Path(__file__).resolve().parent.parent
|
|
72
|
+
cargo_toml = root / "Cargo.toml"
|
|
73
|
+
cargo_lock = root / "Cargo.lock"
|
|
74
|
+
original = cargo_toml.read_text()
|
|
75
|
+
if f'version = "{PLACEHOLDER}"' not in original:
|
|
76
|
+
# CI already stamped the release version; nothing to do.
|
|
77
|
+
yield
|
|
78
|
+
return
|
|
79
|
+
version = _git_version(root)
|
|
80
|
+
if version is None:
|
|
81
|
+
yield
|
|
82
|
+
return
|
|
83
|
+
lock_original = cargo_lock.read_text() if cargo_lock.exists() else None
|
|
84
|
+
cargo_toml.write_text(_VERSION_LINE.sub(f'version = "{version}"', original, count=1))
|
|
85
|
+
try:
|
|
86
|
+
yield
|
|
87
|
+
finally:
|
|
88
|
+
cargo_toml.write_text(original)
|
|
89
|
+
# cargo rewrites the lock to match the patched version during the build.
|
|
90
|
+
if lock_original is not None:
|
|
91
|
+
cargo_lock.write_text(lock_original)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def build_wheel(wheel_directory, config_settings=None, metadata_directory=None):
|
|
95
|
+
with _versioned_cargo_toml():
|
|
96
|
+
return _maturin_build_wheel(wheel_directory, config_settings, metadata_directory)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def build_editable(wheel_directory, config_settings=None, metadata_directory=None):
|
|
100
|
+
with _versioned_cargo_toml():
|
|
101
|
+
return _maturin_build_editable(wheel_directory, config_settings, metadata_directory)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def build_sdist(sdist_directory, config_settings=None):
|
|
105
|
+
with _versioned_cargo_toml():
|
|
106
|
+
return _maturin_build_sdist(sdist_directory, config_settings)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None):
|
|
110
|
+
with _versioned_cargo_toml():
|
|
111
|
+
return _maturin_prepare_metadata_for_build_wheel(metadata_directory, config_settings)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def prepare_metadata_for_build_editable(metadata_directory, config_settings=None):
|
|
115
|
+
with _versioned_cargo_toml():
|
|
116
|
+
return _maturin_prepare_metadata_for_build_editable(metadata_directory, config_settings)
|
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
#
|
|
7
7
|
# Run from the repository root or this directory:
|
|
8
8
|
# python ggroups/generate_g_commands.py
|
|
9
|
-
from pathlib import Path
|
|
10
9
|
import json
|
|
10
|
+
from pathlib import Path
|
|
11
11
|
|
|
12
12
|
json_file = Path(__file__).parent.parent / "python/nc_gcode_interpreter/ggroups.json"
|
|
13
13
|
out_file = Path(__file__).parent.parent / "src/modal_groups.rs"
|
|
14
14
|
|
|
15
|
-
with open(json_file
|
|
15
|
+
with open(json_file) as file:
|
|
16
16
|
g_groups = json.load(file)
|
|
17
17
|
|
|
18
18
|
modal = [g["short_name"] for g in g_groups if g["effectiveness"] == "modal"]
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
[build-system]
|
|
2
2
|
requires = ["maturin>=1.7,<2.0"]
|
|
3
|
-
|
|
3
|
+
# In-tree shim around maturin: stamps a `git describe` version onto the
|
|
4
|
+
# Cargo.toml placeholder so local/editable builds report e.g.
|
|
5
|
+
# 0.2.6.dev3+g1234abc instead of 0.0.0.dev0. See build_backend/.
|
|
6
|
+
build-backend = "nc_build_backend"
|
|
7
|
+
backend-path = ["build_backend"]
|
|
4
8
|
|
|
5
9
|
[project]
|
|
6
10
|
name = "nc-gcode-interpreter"
|
|
@@ -51,6 +55,25 @@ Homepage = "https://github.com/CEAD-group/nc-gcode-interpreter"
|
|
|
51
55
|
Repository = "https://github.com/CEAD-group/nc-gcode-interpreter.git"
|
|
52
56
|
Documentation = "https://github.com/CEAD-group/nc-gcode-interpreter/blob/main/README.md"
|
|
53
57
|
|
|
58
|
+
[tool.ruff]
|
|
59
|
+
target-version = "py312"
|
|
60
|
+
|
|
61
|
+
[tool.ruff.lint]
|
|
62
|
+
# Pin the rule set explicitly. `ruff check .` previously ran on ruff's implicit
|
|
63
|
+
# defaults, so when ruff 0.16 widened them the lint job went red on 64
|
|
64
|
+
# pre-existing findings in code nobody had touched. An explicit select means a
|
|
65
|
+
# ruff upgrade adds rules only when we ask for them.
|
|
66
|
+
select = [
|
|
67
|
+
"E4", "E7", "E9", "F", # ruff's historical defaults
|
|
68
|
+
"I", # import sorting
|
|
69
|
+
"UP", # pyupgrade
|
|
70
|
+
"B", # bugbear
|
|
71
|
+
"C4", # comprehensions
|
|
72
|
+
"PIE",
|
|
73
|
+
"RUF",
|
|
74
|
+
"FLY",
|
|
75
|
+
]
|
|
76
|
+
|
|
54
77
|
[tool.mypy]
|
|
55
78
|
# The viz extra's dependencies are optional: mypy runs in CI without them.
|
|
56
79
|
[[tool.mypy.overrides]]
|
{nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/nc_gcode_interpreter/__init__.py
RENAMED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
import json
|
|
2
2
|
import os
|
|
3
|
+
from collections.abc import Callable, Iterator
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any, Protocol, TypedDict
|
|
6
|
+
|
|
3
7
|
import polars as pl
|
|
4
|
-
|
|
8
|
+
|
|
9
|
+
from ._internal import (
|
|
10
|
+
NcError,
|
|
11
|
+
__doc__, # noqa: F401
|
|
12
|
+
)
|
|
5
13
|
from ._internal import nc_to_batches as _nc_to_batches
|
|
6
|
-
from ._internal import
|
|
7
|
-
from ._internal import __doc__ # noqa: F401
|
|
8
|
-
import json
|
|
9
|
-
from pathlib import Path
|
|
10
|
-
from typing import TypedDict, TypeVar, Any, Generic
|
|
11
|
-
from collections.abc import Callable
|
|
14
|
+
from ._internal import nc_to_rows as _nc_to_rows
|
|
12
15
|
|
|
13
16
|
|
|
14
17
|
# Define TextFileLike Protocol
|
|
@@ -17,12 +20,12 @@ class TextFileLike(Protocol):
|
|
|
17
20
|
|
|
18
21
|
|
|
19
22
|
__all__ = [
|
|
23
|
+
"NcError",
|
|
24
|
+
"dataframe_to_nc",
|
|
25
|
+
"nc_to_batches",
|
|
20
26
|
"nc_to_dataframe",
|
|
21
27
|
"nc_to_rows",
|
|
22
|
-
"nc_to_batches",
|
|
23
28
|
"sanitize_dataframe",
|
|
24
|
-
"dataframe_to_nc",
|
|
25
|
-
"NcError",
|
|
26
29
|
]
|
|
27
30
|
|
|
28
31
|
# Batch size nc_to_dataframe uses internally when draining the batch stream it
|
|
@@ -171,14 +174,11 @@ def nc_to_dataframe(
|
|
|
171
174
|
return pl.concat(frames, how="diagonal").select(frames[-1].columns), state
|
|
172
175
|
|
|
173
176
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
class _classproperty(Generic[_T]):
|
|
178
|
-
def __init__(self, fget: Callable[[Any], _T]) -> None:
|
|
177
|
+
class _classproperty[T]:
|
|
178
|
+
def __init__(self, fget: Callable[[Any], T]) -> None:
|
|
179
179
|
self.fget = fget
|
|
180
180
|
|
|
181
|
-
def __get__(self, instance: Any, owner: type[Any]) ->
|
|
181
|
+
def __get__(self, instance: Any, owner: type[Any]) -> T:
|
|
182
182
|
return self.fget(owner)
|
|
183
183
|
|
|
184
184
|
|
|
@@ -295,10 +295,16 @@ def sanitize_dataframe(
|
|
|
295
295
|
# Canonical column order.
|
|
296
296
|
order: list[str] = []
|
|
297
297
|
for name in (
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
298
|
+
"N",
|
|
299
|
+
*modal,
|
|
300
|
+
*non_modal,
|
|
301
|
+
*known_axes,
|
|
302
|
+
*sorted(c for c in value_columns if c not in known_axes and c not in block_addresses),
|
|
303
|
+
*block_addresses,
|
|
304
|
+
"T",
|
|
305
|
+
"M",
|
|
306
|
+
"non_returning_function_call",
|
|
307
|
+
"comment",
|
|
302
308
|
):
|
|
303
309
|
if name in df.columns and name not in order:
|
|
304
310
|
order.append(name)
|
{nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/nc_gcode_interpreter/_internal.pyi
RENAMED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
from
|
|
1
|
+
from collections.abc import Iterator
|
|
2
|
+
from typing import Any
|
|
2
3
|
|
|
3
4
|
# Type stubs for the compiled Rust extension `nc_gcode_interpreter._internal`.
|
|
4
5
|
# mypy cannot introspect the pyo3 module, so the public entry points the Python
|
|
@@ -13,39 +14,38 @@ class NcError(ValueError):
|
|
|
13
14
|
#: ``"unexpected_axis"``, ``"undefined_variable"``), for branching without
|
|
14
15
|
#: matching the formatted message.
|
|
15
16
|
kind: str
|
|
16
|
-
line:
|
|
17
|
-
column:
|
|
18
|
-
context:
|
|
19
|
-
line_text:
|
|
17
|
+
line: int | None
|
|
18
|
+
column: int | None
|
|
19
|
+
context: str | None
|
|
20
|
+
line_text: str | None
|
|
20
21
|
|
|
21
22
|
def nc_to_rows(
|
|
22
23
|
input: str,
|
|
23
|
-
initial_state:
|
|
24
|
-
axis_identifiers:
|
|
25
|
-
extra_axes:
|
|
24
|
+
initial_state: str | None = None,
|
|
25
|
+
axis_identifiers: list[str] | None = None,
|
|
26
|
+
extra_axes: list[str] | None = None,
|
|
26
27
|
iteration_limit: int = 10000,
|
|
27
28
|
forward_fill: bool = True,
|
|
28
29
|
include_variables: bool = False,
|
|
29
|
-
axis_index_map:
|
|
30
|
+
axis_index_map: dict[str, int] | None = None,
|
|
30
31
|
allow_undefined_variables: bool = False,
|
|
31
32
|
input_is_path: bool = False,
|
|
32
|
-
flatten_tolerance:
|
|
33
|
-
) -> Iterator[
|
|
33
|
+
flatten_tolerance: float | None = None,
|
|
34
|
+
) -> Iterator[tuple[Any, ...]]:
|
|
34
35
|
"""Interpret an NC program lazily into ``(line_no, row[, variables])`` tuples."""
|
|
35
|
-
...
|
|
36
36
|
|
|
37
37
|
def nc_to_batches(
|
|
38
38
|
input: str,
|
|
39
39
|
batch_size: int = 500_000,
|
|
40
|
-
initial_state:
|
|
41
|
-
axis_identifiers:
|
|
42
|
-
extra_axes:
|
|
40
|
+
initial_state: str | None = None,
|
|
41
|
+
axis_identifiers: list[str] | None = None,
|
|
42
|
+
extra_axes: list[str] | None = None,
|
|
43
43
|
iteration_limit: int = 10000,
|
|
44
44
|
disable_forward_fill: bool = False,
|
|
45
|
-
axis_index_map:
|
|
45
|
+
axis_index_map: dict[str, int] | None = None,
|
|
46
46
|
allow_undefined_variables: bool = False,
|
|
47
47
|
input_is_path: bool = False,
|
|
48
|
-
flatten_tolerance:
|
|
48
|
+
flatten_tolerance: float | None = None,
|
|
49
49
|
include_line_numbers: bool = False,
|
|
50
50
|
include_variables: bool = False,
|
|
51
51
|
) -> Any:
|
|
@@ -56,6 +56,5 @@ def nc_to_batches(
|
|
|
56
56
|
- when ``include_variables`` is set - ``variable_events`` (an Arrow batch of
|
|
57
57
|
``row_idx`` / ``name_id`` / ``value``) and ``variable_names`` (list[str]).
|
|
58
58
|
"""
|
|
59
|
-
...
|
|
60
59
|
|
|
61
|
-
__all__ = ["
|
|
60
|
+
__all__ = ["nc_to_batches", "nc_to_rows"]
|
{nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/nc_gcode_interpreter/cli.py
RENAMED
|
@@ -128,8 +128,9 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
128
128
|
args = build_parser().parse_args(argv)
|
|
129
129
|
|
|
130
130
|
try:
|
|
131
|
-
from .viz import view_toolpath
|
|
132
131
|
import threejs_viewer # noqa: F401 - fail here, before interpreting
|
|
132
|
+
|
|
133
|
+
from .viz import view_toolpath
|
|
133
134
|
except ImportError:
|
|
134
135
|
print(
|
|
135
136
|
"nc-view needs the viz extra: pip install 'nc-gcode-interpreter[viz]'",
|
{nc_gcode_interpreter-0.2.6 → nc_gcode_interpreter-0.2.7}/python/nc_gcode_interpreter/viz.py
RENAMED
|
@@ -84,7 +84,7 @@ def toolpath_arrays(
|
|
|
84
84
|
bead_width: float | None = None,
|
|
85
85
|
bead_height: float | None = None,
|
|
86
86
|
default_feed: float = 1000.0,
|
|
87
|
-
) ->
|
|
87
|
+
) -> tuple[np.ndarray, np.ndarray | None]:
|
|
88
88
|
"""Convert an interpreter DataFrame to threejs-viewer toolpath arrays.
|
|
89
89
|
|
|
90
90
|
Returns ``(data, colors)``: ``data`` is the ``(N, 6)`` float64
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""Helper for writing multi-line NC programs in tests."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def nc_lines(*lines: str) -> str:
|
|
5
|
+
"""Join NC blocks into a program, one block per line.
|
|
6
|
+
|
|
7
|
+
Written as varargs rather than `"\\n".join([...])` so each block can carry
|
|
8
|
+
its own trailing `#` comment explaining what it contributes to the expected
|
|
9
|
+
output - which is most of why these programs are written a line at a time.
|
|
10
|
+
"""
|
|
11
|
+
return "\n".join(lines)
|