laterite 0.5.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.
Files changed (127) hide show
  1. laterite-0.5.0/LICENSE +34 -0
  2. laterite-0.5.0/PKG-INFO +87 -0
  3. laterite-0.5.0/README.md +52 -0
  4. laterite-0.5.0/pyproject.toml +96 -0
  5. laterite-0.5.0/python/laterite/README-cli.md +97 -0
  6. laterite-0.5.0/python/laterite/__init__.py +1374 -0
  7. laterite-0.5.0/python/laterite/_cli.py +283 -0
  8. laterite-0.5.0/python/laterite/_compat_desc.py +352 -0
  9. laterite-0.5.0/python/laterite/_errors.py +77 -0
  10. laterite-0.5.0/python/laterite/_frames.py +109 -0
  11. laterite-0.5.0/python/laterite/_laterite_native.pyi +8749 -0
  12. laterite-0.5.0/python/laterite/ags4.py +300 -0
  13. laterite-0.5.0/python/laterite/ags_types.py +83 -0
  14. laterite-0.5.0/python/laterite/compat.py +1660 -0
  15. laterite-0.5.0/python/laterite/dynamic.py +186 -0
  16. laterite-0.5.0/python/laterite/py.typed +0 -0
  17. laterite-0.5.0/python/laterite/registry.py +144 -0
  18. laterite-0.5.0/python/laterite/transport.py +173 -0
  19. laterite-0.5.0/rust-packages/Cargo.lock +3867 -0
  20. laterite-0.5.0/rust-packages/Cargo.toml +59 -0
  21. laterite-0.5.0/rust-packages/laterite-ags4-core/Cargo.toml +75 -0
  22. laterite-0.5.0/rust-packages/laterite-ags4-core/data/ags_dictionary.json +62639 -0
  23. laterite-0.5.0/rust-packages/laterite-ags4-core/data/recipes.md +190 -0
  24. laterite-0.5.0/rust-packages/laterite-ags4-core/data/sensitive_headings.json +2148 -0
  25. laterite-0.5.0/rust-packages/laterite-ags4-core/src/ags4_codec.rs +270 -0
  26. laterite-0.5.0/rust-packages/laterite-ags4-core/src/error.rs +97 -0
  27. laterite-0.5.0/rust-packages/laterite-ags4-core/src/index.rs +786 -0
  28. laterite-0.5.0/rust-packages/laterite-ags4-core/src/keychain.rs +324 -0
  29. laterite-0.5.0/rust-packages/laterite-ags4-core/src/lib.rs +31 -0
  30. laterite-0.5.0/rust-packages/laterite-ags4-core/src/registry.rs +411 -0
  31. laterite-0.5.0/rust-packages/laterite-ags4-core/src/transport.rs +163 -0
  32. laterite-0.5.0/rust-packages/laterite-ags4-core/tests/byte_offset_ground_truth.rs +57 -0
  33. laterite-0.5.0/rust-packages/laterite-ags4-core/tests/error_mapping.rs +39 -0
  34. laterite-0.5.0/rust-packages/laterite-ags4-core/tests/fixtures/.gitattributes +6 -0
  35. laterite-0.5.0/rust-packages/laterite-ags4-core/tests/fixtures/leading_blank.ags +12 -0
  36. laterite-0.5.0/rust-packages/laterite-ags4-core/tests/fixtures/quoted_newline.ags +11 -0
  37. laterite-0.5.0/rust-packages/laterite-ags4-core/tests/fixtures/two_group_bom.ags +10 -0
  38. laterite-0.5.0/rust-packages/laterite-ags4-core/tests/fixtures/two_group_crlf.ags +10 -0
  39. laterite-0.5.0/rust-packages/laterite-ags4-core/tests/fixtures/two_group_lf.ags +10 -0
  40. laterite-0.5.0/rust-packages/laterite-ags4-diff/Cargo.toml +39 -0
  41. laterite-0.5.0/rust-packages/laterite-ags4-diff/src/lib.rs +417 -0
  42. laterite-0.5.0/rust-packages/laterite-ags4-emit/Cargo.toml +51 -0
  43. laterite-0.5.0/rust-packages/laterite-ags4-emit/src/arrow_in.rs +124 -0
  44. laterite-0.5.0/rust-packages/laterite-ags4-emit/src/emit.rs +394 -0
  45. laterite-0.5.0/rust-packages/laterite-ags4-emit/src/error.rs +39 -0
  46. laterite-0.5.0/rust-packages/laterite-ags4-emit/src/lib.rs +24 -0
  47. laterite-0.5.0/rust-packages/laterite-ags4-emit/src/writer.rs +158 -0
  48. laterite-0.5.0/rust-packages/laterite-ags4-parse/Cargo.toml +27 -0
  49. laterite-0.5.0/rust-packages/laterite-ags4-parse/src/lib.rs +532 -0
  50. laterite-0.5.0/rust-packages/laterite-ags4-parse/tests/byte_walk.rs +191 -0
  51. laterite-0.5.0/rust-packages/laterite-ags4-parse/tests/dep_graph.rs +59 -0
  52. laterite-0.5.0/rust-packages/laterite-ags4-parse/tests/split_field.rs +135 -0
  53. laterite-0.5.0/rust-packages/laterite-ags4-parse/tests/strict_structure.rs +73 -0
  54. laterite-0.5.0/rust-packages/laterite-ags4-validator/Cargo.toml +91 -0
  55. laterite-0.5.0/rust-packages/laterite-ags4-validator/README.md +82 -0
  56. laterite-0.5.0/rust-packages/laterite-ags4-validator/benches/validate_large_fixture.rs +38 -0
  57. laterite-0.5.0/rust-packages/laterite-ags4-validator/build.rs +390 -0
  58. laterite-0.5.0/rust-packages/laterite-ags4-validator/data/PROVENANCE.md +79 -0
  59. laterite-0.5.0/rust-packages/laterite-ags4-validator/data/Standard_dictionary_v4_0_3.ags +3088 -0
  60. laterite-0.5.0/rust-packages/laterite-ags4-validator/data/Standard_dictionary_v4_0_4.ags +3095 -0
  61. laterite-0.5.0/rust-packages/laterite-ags4-validator/data/Standard_dictionary_v4_1.ags +6396 -0
  62. laterite-0.5.0/rust-packages/laterite-ags4-validator/data/Standard_dictionary_v4_1_1.ags +6393 -0
  63. laterite-0.5.0/rust-packages/laterite-ags4-validator/data/Standard_dictionary_v4_2.ags +7225 -0
  64. laterite-0.5.0/rust-packages/laterite-ags4-validator/data/rules_meta.json +412 -0
  65. laterite-0.5.0/rust-packages/laterite-ags4-validator/src/catalogue.rs +150 -0
  66. laterite-0.5.0/rust-packages/laterite-ags4-validator/src/dict.rs +347 -0
  67. laterite-0.5.0/rust-packages/laterite-ags4-validator/src/error.rs +80 -0
  68. laterite-0.5.0/rust-packages/laterite-ags4-validator/src/findings.rs +241 -0
  69. laterite-0.5.0/rust-packages/laterite-ags4-validator/src/fixes.rs +1451 -0
  70. laterite-0.5.0/rust-packages/laterite-ags4-validator/src/lib.rs +462 -0
  71. laterite-0.5.0/rust-packages/laterite-ags4-validator/src/parse.rs +188 -0
  72. laterite-0.5.0/rust-packages/laterite-ags4-validator/src/rules/dictionary.rs +305 -0
  73. laterite-0.5.0/rust-packages/laterite-ags4-validator/src/rules/groups.rs +1043 -0
  74. laterite-0.5.0/rust-packages/laterite-ags4-validator/src/rules/line_format.rs +466 -0
  75. laterite-0.5.0/rust-packages/laterite-ags4-validator/src/rules/mod.rs +56 -0
  76. laterite-0.5.0/rust-packages/laterite-ags4-validator/src/rules/naming.rs +298 -0
  77. laterite-0.5.0/rust-packages/laterite-ags4-validator/src/rules/references.rs +613 -0
  78. laterite-0.5.0/rust-packages/laterite-ags4-validator/src/rules/relational.rs +1094 -0
  79. laterite-0.5.0/rust-packages/laterite-ags4-validator/src/rules/structure.rs +455 -0
  80. laterite-0.5.0/rust-packages/laterite-ags4-validator/src/rules/typed_values.rs +977 -0
  81. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/clean_minimal.ags +25 -0
  82. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/rule10a_dup_key.ags +6 -0
  83. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/rule10c_orphan_child.ags +12 -0
  84. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/rule11c_bad_rl.ags +17 -0
  85. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/rule13_no_proj.ags +17 -0
  86. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/rule15_unit_undef.ags +31 -0
  87. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/rule16_fyi_nonstandard_abbr.ags +23 -0
  88. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/rule17_no_type.ags +17 -0
  89. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/rule18_malformed_dict.ags +12 -0
  90. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/rule19_bad_group_name.ags +5 -0
  91. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/rule19a_bad_heading.ags +5 -0
  92. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/rule19b_bad_prefix.ags +5 -0
  93. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/rule19b_borrowed_bad.ags +5 -0
  94. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/rule1_non_ascii.ags +5 -0
  95. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/rule20_undefined_fset.ags +11 -0
  96. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/rule2_no_data_rows.ags +10 -0
  97. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/rule2b_unit_missing.ags +4 -0
  98. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/rule3_bad_descriptor.ags +6 -0
  99. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/rule4_field_count.ags +5 -0
  100. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/rule5_unquoted.ags +5 -0
  101. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/rule7_out_of_order.ags +5 -0
  102. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/rule8_dp_wrong_precision.ags +5 -0
  103. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/rule8_dt_bad.ags +5 -0
  104. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/rule8_dt_empty_unit.ags +5 -0
  105. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/rule8_dt_out_of_range.ags +5 -0
  106. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/rule9_unknown_heading.ags +5 -0
  107. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/fixtures/synthetic_multigroup.ags +91 -0
  108. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/lean_dep_graph.rs +75 -0
  109. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/line_contract.rs +91 -0
  110. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/parse_parity.rs +146 -0
  111. laterite-0.5.0/rust-packages/laterite-ags4-validator/tests/regression.rs +579 -0
  112. laterite-0.5.0/rust-packages/laterite-excel/Cargo.toml +37 -0
  113. laterite-0.5.0/rust-packages/laterite-excel/src/lib.rs +784 -0
  114. laterite-0.5.0/rust-packages/laterite-py/Cargo.toml +104 -0
  115. laterite-0.5.0/rust-packages/laterite-py/build.rs +283 -0
  116. laterite-0.5.0/rust-packages/laterite-py/src/ags_types_fns.rs +176 -0
  117. laterite-0.5.0/rust-packages/laterite-py/src/emit.rs +69 -0
  118. laterite-0.5.0/rust-packages/laterite-py/src/emit_typed.rs +206 -0
  119. laterite-0.5.0/rust-packages/laterite-py/src/excel_fns.rs +69 -0
  120. laterite-0.5.0/rust-packages/laterite-py/src/lib.rs +1017 -0
  121. laterite-0.5.0/rust-packages/laterite-py/src/registry_fns.rs +80 -0
  122. laterite-0.5.0/rust-packages/laterite-py/src/transport_fns.rs +102 -0
  123. laterite-0.5.0/rust-packages/laterite-py/src/typed_graph/mod.rs +41 -0
  124. laterite-0.5.0/rust-packages/laterite-types/Cargo.toml +51 -0
  125. laterite-0.5.0/rust-packages/laterite-types/src/arrow_cols.rs +128 -0
  126. laterite-0.5.0/rust-packages/laterite-types/src/ipc.rs +83 -0
  127. laterite-0.5.0/rust-packages/laterite-types/src/lib.rs +967 -0
laterite-0.5.0/LICENSE ADDED
@@ -0,0 +1,34 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 niko86
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.
22
+
23
+ ---
24
+
25
+ Third-party data notice:
26
+
27
+ The AGS4 standard data dictionaries bundled under
28
+ `rust-packages/laterite-ags4-validator/data/` (`Standard_dictionary_v4_1.ags`,
29
+ `Standard_dictionary_v4_2.ags`) are © The Association of Geotechnical and
30
+ Geoenvironmental Specialists (AGS), all rights reserved. They are reference
31
+ data for the published AGS4 transfer-format standard, redistributed here as
32
+ a documented decision — see that directory's `PROVENANCE.md`. This MIT
33
+ licence covers the source code of this repository; it does not purport to
34
+ relicense the AGS dictionary data.
@@ -0,0 +1,87 @@
1
+ Metadata-Version: 2.4
2
+ Name: laterite
3
+ Version: 0.5.0
4
+ Classifier: Development Status :: 3 - Alpha
5
+ Classifier: License :: OSI Approved :: MIT License
6
+ Classifier: Programming Language :: Python :: 3.12
7
+ Classifier: Programming Language :: Python :: 3.13
8
+ Classifier: Programming Language :: Python :: 3.14
9
+ Classifier: Programming Language :: Rust
10
+ Classifier: Topic :: Scientific/Engineering
11
+ Classifier: Typing :: Typed
12
+ Requires-Dist: polars>=1.40.1
13
+ Requires-Dist: duckdb>=1.4.0
14
+ Requires-Dist: pandas<3 ; extra == 'all'
15
+ Requires-Dist: pyarrow>=24.0.0 ; extra == 'all'
16
+ Requires-Dist: pandas<3 ; extra == 'compat'
17
+ Requires-Dist: pandas<3 ; extra == 'pandas'
18
+ Requires-Dist: pyarrow>=24.0.0 ; extra == 'pyarrow'
19
+ Provides-Extra: all
20
+ Provides-Extra: compat
21
+ Provides-Extra: pandas
22
+ Provides-Extra: pyarrow
23
+ License-File: LICENSE
24
+ Summary: Rust-backed AGS4 reader/writer/validator — a fast, drop-in replacement for python-ags4 with born-typed polars/pandas reads (pyarrow-free)
25
+ Keywords: ags,ags4,geotechnical,ground-investigation,validator,parser,rust,polars,pandas,duckdb
26
+ Author-email: niko86 <me@niko86.com>
27
+ License-Expression: MIT
28
+ Requires-Python: >=3.12
29
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
30
+ Project-URL: Changelog, https://github.com/niko86/laterite/blob/main/CHANGELOG.md
31
+ Project-URL: Homepage, https://github.com/niko86/laterite
32
+ Project-URL: Issues, https://github.com/niko86/laterite/issues
33
+ Project-URL: Repository, https://github.com/niko86/laterite
34
+
35
+ <p align="center">
36
+ <img src="https://raw.githubusercontent.com/niko86/laterite/main/assets/laterite-social-preview-white.png" alt="laterite — a Rust-backed AGS4 reader, writer and validator" width="600" />
37
+ </p>
38
+
39
+ # laterite
40
+
41
+ A Rust-backed AGS4 reader, writer and validator for Python.
42
+
43
+ A faster drop-in for
44
+ [`python-ags4`](https://gitlab.com/ags-data-format-wg/ags-python-library)'s
45
+ `AGS4` module (1.2.0 parity-pinned, 122/131 tests) — swap
46
+ `from python_ags4 import AGS4` for `from laterite import compat as AGS4`.
47
+ The native API returns born-typed **polars** frames by default (or
48
+ **pandas** with `read(..., backend="pandas")`) — both **pyarrow-free**,
49
+ read back from a Python-owned in-memory DuckDB engine.
50
+
51
+ [![ci](https://github.com/niko86/laterite/actions/workflows/ci.yml/badge.svg)](https://github.com/niko86/laterite/actions/workflows/ci.yml)
52
+ [![rust cov](https://img.shields.io/codecov/c/github/niko86/laterite?flag=rust&label=rust%20cov)](https://codecov.io/gh/niko86/laterite)
53
+ [![python cov](https://img.shields.io/codecov/c/github/niko86/laterite?flag=python&label=python%20cov)](https://codecov.io/gh/niko86/laterite)
54
+ [![web cov](https://img.shields.io/codecov/c/github/niko86/laterite?flag=web&label=web%20cov)](https://codecov.io/gh/niko86/laterite)
55
+ [![PyPI](https://img.shields.io/pypi/v/laterite.svg)](https://pypi.org/project/laterite/)
56
+ [![Python versions](https://img.shields.io/pypi/pyversions/laterite.svg)](https://pypi.org/project/laterite/)
57
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
58
+
59
+ ```bash
60
+ pip install laterite # base AGS4 (polars + duckdb, pyarrow-free)
61
+ pip install "laterite[compat]" # + pandas (python-ags4 drop-in)
62
+ ```
63
+
64
+ ```python
65
+ import laterite
66
+
67
+ result = laterite.validate("delivery.ags")
68
+ for rule, findings in result.by_rule().items():
69
+ print(rule, len(findings))
70
+
71
+ # python-ags4 drop-in
72
+ from laterite import compat as AGS4
73
+ tables, _ = AGS4.AGS4_to_dataframe("delivery.ags")
74
+
75
+ # Or a typed view of the file
76
+ from laterite.ags4 import read_typed
77
+ proj = read_typed("delivery.ags")
78
+ ```
79
+
80
+ The validator engine is clean-room from the AGS4 spec. python-ags4
81
+ is LGPL-3.0; the clean-room separation lets laterite ship under MIT.
82
+
83
+ Requires Python ≥ 3.12.
84
+
85
+ Full docs, parity catalogue and observations at
86
+ <https://github.com/niko86/laterite>.
87
+
@@ -0,0 +1,52 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/niko86/laterite/main/assets/laterite-social-preview-white.png" alt="laterite — a Rust-backed AGS4 reader, writer and validator" width="600" />
3
+ </p>
4
+
5
+ # laterite
6
+
7
+ A Rust-backed AGS4 reader, writer and validator for Python.
8
+
9
+ A faster drop-in for
10
+ [`python-ags4`](https://gitlab.com/ags-data-format-wg/ags-python-library)'s
11
+ `AGS4` module (1.2.0 parity-pinned, 122/131 tests) — swap
12
+ `from python_ags4 import AGS4` for `from laterite import compat as AGS4`.
13
+ The native API returns born-typed **polars** frames by default (or
14
+ **pandas** with `read(..., backend="pandas")`) — both **pyarrow-free**,
15
+ read back from a Python-owned in-memory DuckDB engine.
16
+
17
+ [![ci](https://github.com/niko86/laterite/actions/workflows/ci.yml/badge.svg)](https://github.com/niko86/laterite/actions/workflows/ci.yml)
18
+ [![rust cov](https://img.shields.io/codecov/c/github/niko86/laterite?flag=rust&label=rust%20cov)](https://codecov.io/gh/niko86/laterite)
19
+ [![python cov](https://img.shields.io/codecov/c/github/niko86/laterite?flag=python&label=python%20cov)](https://codecov.io/gh/niko86/laterite)
20
+ [![web cov](https://img.shields.io/codecov/c/github/niko86/laterite?flag=web&label=web%20cov)](https://codecov.io/gh/niko86/laterite)
21
+ [![PyPI](https://img.shields.io/pypi/v/laterite.svg)](https://pypi.org/project/laterite/)
22
+ [![Python versions](https://img.shields.io/pypi/pyversions/laterite.svg)](https://pypi.org/project/laterite/)
23
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
24
+
25
+ ```bash
26
+ pip install laterite # base AGS4 (polars + duckdb, pyarrow-free)
27
+ pip install "laterite[compat]" # + pandas (python-ags4 drop-in)
28
+ ```
29
+
30
+ ```python
31
+ import laterite
32
+
33
+ result = laterite.validate("delivery.ags")
34
+ for rule, findings in result.by_rule().items():
35
+ print(rule, len(findings))
36
+
37
+ # python-ags4 drop-in
38
+ from laterite import compat as AGS4
39
+ tables, _ = AGS4.AGS4_to_dataframe("delivery.ags")
40
+
41
+ # Or a typed view of the file
42
+ from laterite.ags4 import read_typed
43
+ proj = read_typed("delivery.ags")
44
+ ```
45
+
46
+ The validator engine is clean-room from the AGS4 spec. python-ags4
47
+ is LGPL-3.0; the clean-room separation lets laterite ship under MIT.
48
+
49
+ Requires Python ≥ 3.12.
50
+
51
+ Full docs, parity catalogue and observations at
52
+ <https://github.com/niko86/laterite>.
@@ -0,0 +1,96 @@
1
+ [project]
2
+ name = "laterite"
3
+ version = "0.5.0"
4
+ description = "Rust-backed AGS4 reader/writer/validator — a fast, drop-in replacement for python-ags4 with born-typed polars/pandas reads (pyarrow-free)"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ authors = [{ name = "niko86", email = "me@niko86.com" }]
9
+ keywords = [
10
+ "ags",
11
+ "ags4",
12
+ "geotechnical",
13
+ "ground-investigation",
14
+ "validator",
15
+ "parser",
16
+ "rust",
17
+ "polars",
18
+ "pandas",
19
+ "duckdb",
20
+ ]
21
+ classifiers = [
22
+ "Development Status :: 3 - Alpha",
23
+ "License :: OSI Approved :: MIT License",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
26
+ "Programming Language :: Python :: 3.14",
27
+ "Programming Language :: Rust",
28
+ "Topic :: Scientific/Engineering",
29
+ "Typing :: Typed",
30
+ ]
31
+ requires-python = ">=3.12"
32
+ # Mandatory runtime deps:
33
+ # polars — the default frame backend; the read boundary hands Rust-built
34
+ # Arrow over zero-copy (a pyo3-arrow capsule), loaded into DuckDB,
35
+ # and materialised back pyarrow-free into born-typed polars frames.
36
+ # duckdb — the Python-owned in-memory engine: read() loads each group into a
37
+ # born-typed DuckDB table, so ags[code] / ags.sql(...) run real
38
+ # cross-group joins + filter pushdown. NOT bundled in the wheel (the
39
+ # CLI keeps its own); needs no pinned storage version. Floor >=1.4.0
40
+ # (LTS line, in-memory COMPRESS).
41
+ # narwhals is GONE — the core returns polars / pandas directly and `compat`
42
+ # branches on the native frame; nothing imports narwhals at runtime.
43
+ # pyarrow is NOT a laterite dependency anywhere — not base, not the [compat] extra.
44
+ # The polars path uses the Arrow C-stream capsule; the pandas path (core AND compat)
45
+ # uses DuckDB's NumPy `.df()`; both are pyarrow-free. An Arrow table is only reachable
46
+ # via `ags.connection` (or the explicit `pyarrow` backend/extra) with the user's own
47
+ # pyarrow. pandas is an optional extra; a python-ags4 install pulls pandas in
48
+ # unconditionally, laterite does not.
49
+ dependencies = [
50
+ "polars>=1.40.1",
51
+ "duckdb>=1.4.0",
52
+ ]
53
+
54
+ [project.urls]
55
+ Homepage = "https://github.com/niko86/laterite"
56
+ Repository = "https://github.com/niko86/laterite"
57
+ Issues = "https://github.com/niko86/laterite/issues"
58
+ Changelog = "https://github.com/niko86/laterite/blob/main/CHANGELOG.md"
59
+
60
+ # `compat` is the python-ags4 drop-in surface — it defaults to returning
61
+ # pandas frames, so `pip install laterite[compat]` is what most callers
62
+ # want when porting from python_ags4. `pandas` is retained as a
63
+ # back-compat alias (same set). `set_backend("polars")` (or
64
+ # LATERITE_COMPAT_BACKEND=polars) removes the pandas requirement entirely.
65
+ [project.optional-dependencies]
66
+ # compat (the python-ags4 drop-in, pandas by default) is now pyarrow-free: its pandas
67
+ # output goes polars -> pandas via DuckDB's NumPy `.df()` (the same trick the core
68
+ # uses), so the extra is just pandas. `pandas` is a back-compat alias of `compat`;
69
+ # `pyarrow` stays for callers who explicitly want the Arrow backend (the only thing
70
+ # that pulls pyarrow).
71
+ compat = ["pandas<3"]
72
+ pandas = ["pandas<3"]
73
+ pyarrow = ["pyarrow>=24.0.0"]
74
+ # The experimental DuckDB-backed `.ags5db` surface was decoupled from the
75
+ # shipped AGS4 product (#177) — it now lives in the dormant `ags5/` holding
76
+ # folder and is no longer installable as an extra. The future AGS5 strand
77
+ # will publish it as a separate library.
78
+ all = ["pandas<3", "pyarrow>=24.0.0"]
79
+
80
+ [project.scripts]
81
+ # Deliberately named `lat-check` (not `laterite`/`ags4`) so the command,
82
+ # its flags, JSON/NDJSON shape and exit codes are byte-faithful to the
83
+ # Rust `lat-check` binary. This is the Python face of the same CLI.
84
+ lat-check = "laterite._cli:main"
85
+
86
+ [build-system]
87
+ requires = ["maturin>=1.7,<2"]
88
+ build-backend = "maturin"
89
+
90
+ [tool.maturin]
91
+ module-name = "laterite._laterite_native"
92
+ manifest-path = "rust-packages/laterite-py/Cargo.toml"
93
+ python-source = "python"
94
+ # abi3 (cp312-abi3): laterite-py/Cargo.toml sets `abi3-py312` on pyo3, so
95
+ # maturin emits ONE `cp312-abi3` wheel per platform that runs on Python 3.12+.
96
+ # (The old "pinned to 3.14 / pyo3-polars couples the wheel" note was wrong — the
@@ -0,0 +1,97 @@
1
+ # lat-check
2
+
3
+ A clean-room Rust validator for the **AGS4** geotechnical
4
+ transfer-format — the capability `python-ags4`'s `AGS4.check_file()`
5
+ provides, with no Python at runtime. Reports the numbered AGS Format
6
+ Rule violations in a file.
7
+
8
+ ## Usage
9
+
10
+ lat-check <file.ags> [options]
11
+ lat-check --readme # this document
12
+
13
+ ## Options
14
+
15
+ --dict-version <V> bundled dictionary edition:
16
+ auto (default — picked from the file's
17
+ TRAN_AGS) | 4.0.3 | 4.0.4 | 4.1 | 4.1.1 | 4.2
18
+ --dict <path> external dictionary override (not supported)
19
+ --json machine-readable findings (pretty JSON)
20
+ --ndjson one flat JSON object per finding per line
21
+ --out <path> write the active format to <path> instead of
22
+ stdout (prints a one-line confirmation)
23
+ --json-out <path> also tee the JSON report to <path>
24
+ --fix mechanically repair the file: apply the SAFE
25
+ fixes (CRLF / BOM / embedded-CR / short-row pad /
26
+ numeric reformat / TRAN delimiter+concatenator
27
+ rows) and write the result. Non-destructive —
28
+ writes a sibling <file>.fixed.ags by default.
29
+ Exit 0 if the repaired file is clean, 1 if
30
+ findings remain that can't be auto-fixed.
31
+ --fix-risky like --fix but ALSO applies the intent-guessing
32
+ fixes (duplicate-heading rename, dd/mm date
33
+ canonicalisation, smart-quote→ASCII typography)
34
+ --in-place with --fix: overwrite the source file in place
35
+ --fix-out <path> with --fix: write the repaired file to <path>
36
+ --diff <other.ags> compare the input file against <other> and print the
37
+ KEY-aware/type-aware revision delta (per-group
38
+ +added -removed ~changed; --json for the full delta)
39
+ --no-warnings errors only — suppress the WARNING tier, which is
40
+ shown by default (malformed DICT, nonstandard
41
+ abbreviations, unrecognised TRAN_AGS edition)
42
+ --show-fyi include FYI-severity findings (e.g. Rule 1)
43
+ --check-files also run Rule 20's on-disk check: the sidecar
44
+ FILE/<fset>/<name> tree must exist next to the
45
+ .ags. Default OFF — data-level Rule 20 is
46
+ path-independent (the library default); enable
47
+ for a packaging/QA pass on a real delivery.
48
+ --encoding <name> source text encoding for legacy extended-ASCII
49
+ files: utf-8 (default) | cp1252 | latin1 |
50
+ iso-8859-1 | iso-8859-15. latin1 / iso-8859-1
51
+ map to Windows-1252 (the CP1252 superset
52
+ python-ags4 uses by default).
53
+ --list-rules print the AGS4 rule catalogue (title / severity /
54
+ fixable / cited observations) and exit; add --json
55
+ for the full machine-readable form. No input file.
56
+ --quiet suppress the progress spinner
57
+ --tui interactive findings browser (needs the
58
+ `tui` build feature + an interactive terminal)
59
+ --readme print this document and exit
60
+ -h, --help short usage
61
+
62
+ ## Dictionary auto-selection
63
+
64
+ By default the edition is chosen **per file from its `TRAN_AGS`**:
65
+ an exact bundled match wins (`4.0.3/4.0.4/4.1/4.1.1/4.2`), else the
66
+ newest bundled patch of that `major.minor` (`4.0`→4.0.4, `4.1.5`→
67
+ 4.1.1), else a fallback to 4.1.1 (matching python-ags4's
68
+ `LATEST_DICT_VERSION`). AGS 3.x is refused (exit 4) rather than
69
+ silently validated against an AGS4 schema. `--dict-version` forces
70
+ one edition regardless.
71
+
72
+ ## Output
73
+
74
+ Human table on a TTY (coloured unless `NO_COLOR`); `--json` for a
75
+ nested `{file, findings:{rule:[{line,group,desc}]}}` document;
76
+ `--ndjson` for a stream. Progress is on stderr; the report on stdout.
77
+
78
+ ## Exit codes
79
+
80
+ 0 clean (no findings)
81
+ 1 findings present
82
+ 3 file not found / unreadable
83
+ 4 not UTF-8 / not an AGS4 file / unsupported AGS edition (3.x)
84
+ 5 bad arguments / bad dictionary
85
+
86
+ ## Examples
87
+
88
+ lat-check delivery.ags # human table
89
+ lat-check delivery.ags --json | jq . # machine-readable
90
+ lat-check delivery.ags --dict-version 4.2 # force an edition
91
+ lat-check delivery.ags --show-fyi --out report.txt
92
+ lat-check delivery.ags --fix # → delivery.fixed.ags
93
+ lat-check delivery.ags --fix --in-place # repair in place
94
+ lat-check delivery.ags --fix-risky --fix-out clean.ags
95
+
96
+ > The clean-room boundary, licence, and bundled-dictionary provenance
97
+ > are documented in the crate's `README.md` and `data/PROVENANCE.md`.