lvpath 0.3.1__tar.gz → 1.0.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.
- {lvpath-0.3.1 → lvpath-1.0.0}/.gitignore +2 -0
- lvpath-1.0.0/CHANGELOG.md +140 -0
- {lvpath-0.3.1 → lvpath-1.0.0}/CONTRIBUTING.md +19 -19
- lvpath-1.0.0/GUIDE.md +290 -0
- {lvpath-0.3.1 → lvpath-1.0.0}/LICENSE +21 -21
- lvpath-1.0.0/PKG-INFO +147 -0
- lvpath-1.0.0/README.md +110 -0
- {lvpath-0.3.1 → lvpath-1.0.0}/pyproject.toml +16 -5
- {lvpath-0.3.1 → lvpath-1.0.0}/src/lvpath/__init__.py +9 -9
- lvpath-1.0.0/src/lvpath/__main__.py +10 -0
- lvpath-1.0.0/src/lvpath/_cli.py +177 -0
- lvpath-1.0.0/src/lvpath/_coerce.py +34 -0
- lvpath-1.0.0/src/lvpath/_convert.py +86 -0
- lvpath-1.0.0/src/lvpath/_fields.py +71 -0
- lvpath-1.0.0/src/lvpath/_flatbridge.py +125 -0
- lvpath-1.0.0/src/lvpath/_flatten.py +173 -0
- {lvpath-0.3.1 → lvpath-1.0.0}/src/lvpath/_kinds.py +20 -1
- {lvpath-0.3.1 → lvpath-1.0.0}/src/lvpath/_platform.py +26 -6
- {lvpath-0.3.1 → lvpath-1.0.0}/src/lvpath/_portable.py +56 -31
- lvpath-1.0.0/src/lvpath/_text.py +29 -0
- lvpath-1.0.0/tests/conftest.py +59 -0
- lvpath-1.0.0/tests/fixtures/labview2026_flat.json +98 -0
- lvpath-1.0.0/tests/fixtures/sources/MANIFEST.json +13 -0
- {lvpath-0.3.1 → lvpath-1.0.0}/tests/test_cli.py +13 -3
- {lvpath-0.3.1 → lvpath-1.0.0}/tests/test_cli_e2e.py +12 -24
- lvpath-1.0.0/tests/test_cli_e2e_more.py +60 -0
- lvpath-1.0.0/tests/test_contract_one.py +156 -0
- lvpath-1.0.0/tests/test_contract_review.py +50 -0
- lvpath-1.0.0/tests/test_contract_strength.py +63 -0
- lvpath-1.0.0/tests/test_contract_three.py +100 -0
- lvpath-1.0.0/tests/test_contract_two.py +140 -0
- lvpath-1.0.0/tests/test_docs.py +114 -0
- {lvpath-0.3.1 → lvpath-1.0.0}/tests/test_flatten.py +1 -1
- lvpath-1.0.0/tests/test_fuzz.py +134 -0
- lvpath-1.0.0/tests/test_packaging.py +64 -0
- lvpath-1.0.0/tests/test_real_labview_flat.py +149 -0
- lvpath-1.0.0/tests/test_sources_truth.py +60 -0
- lvpath-0.3.1/CHANGELOG.md +0 -58
- lvpath-0.3.1/PKG-INFO +0 -271
- lvpath-0.3.1/README.md +0 -244
- lvpath-0.3.1/src/lvpath/_cli.py +0 -134
- lvpath-0.3.1/src/lvpath/_convert.py +0 -48
- lvpath-0.3.1/src/lvpath/_flatbridge.py +0 -69
- lvpath-0.3.1/src/lvpath/_flatten.py +0 -139
- {lvpath-0.3.1 → lvpath-1.0.0}/src/lvpath/py.typed +0 -0
- {lvpath-0.3.1 → lvpath-1.0.0}/tests/fixtures/labview2026_paths.json +0 -0
- {lvpath-0.3.1 → lvpath-1.0.0}/tests/test_contract.py +0 -0
- {lvpath-0.3.1 → lvpath-1.0.0}/tests/test_convert.py +0 -0
- {lvpath-0.3.1 → lvpath-1.0.0}/tests/test_flatten_contract.py +0 -0
- {lvpath-0.3.1 → lvpath-1.0.0}/tests/test_portable.py +0 -0
- {lvpath-0.3.1 → lvpath-1.0.0}/tests/test_portable_contract.py +0 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses
|
|
5
|
+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [1.0.0] - 2026-10-15
|
|
10
|
+
|
|
11
|
+
The public surface is now stable: the seventeen names of 0.3.1 (three of them exception classes) with the same
|
|
12
|
+
parameters and defaults (some annotations widened, listed below), the `lvpath` command and `python -m lvpath`.
|
|
13
|
+
The flattened form is checked against NI's published example and against the
|
|
14
|
+
349,566 flattened paths LabVIEW 2026 stores in its own installed files.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- An empty flattened component now decodes as `..` and `..` encodes as an empty
|
|
19
|
+
component, which is how LabVIEW 2026 stores relative links (21,765 links in its own
|
|
20
|
+
files resolve that way). 0.3.1 dropped the empty components, so
|
|
21
|
+
`('', '', 'NI_MDF.lvlib')` decoded as `NI_MDF.lvlib`, and wrote `..` as two dots.
|
|
22
|
+
- `<Not A Path>` in the flattened form is path type 2 with no component, the code
|
|
23
|
+
LabVIEW's `cintools/extcode.h` gives it and the record LabVIEW 2026 stores in
|
|
24
|
+
`resource/labview.rsc`. `to_flat_path("")` and `to_flat_path(None)` now write it (0.3.1
|
|
25
|
+
wrote `""` as an empty relative path, which decodes as `.`, and raised
|
|
26
|
+
`AttributeError` for `None`), and `from_flat_path` raises `NotAPathError` for it (0.3.1:
|
|
27
|
+
`FlatPathError`). `FlatPathType` gains `NOT_A_PATH` (2) and `UNC` (3); a UNC flattened
|
|
28
|
+
path is still refused with `FlatPathError`.
|
|
29
|
+
- `from_flat_path` refuses with `FlatPathError` what 0.3.1 misread: a symbolic
|
|
30
|
+
`<vilib>`-style first component of an absolute path, a first Windows component that is
|
|
31
|
+
not one drive letter (0.3.1 produced `usr:\lib`), literal `.` and `..` components, and
|
|
32
|
+
components holding `/` (or `\` or `:` on Windows).
|
|
33
|
+
- `to_flat_path` refuses a POSIX path starting with `//` (0.3.1 dropped one slash) and a
|
|
34
|
+
rooted Windows path without a drive such as `\usr\x` (0.3.1 wrote it as a relative path
|
|
35
|
+
whose first component was a backslash).
|
|
36
|
+
- One flavor rule for `PurePath` arguments in every function: a `PurePath` keeps its own
|
|
37
|
+
flavor unless `platform` names the other one, and then only a relative path may cross,
|
|
38
|
+
with no backslash or colon inside a component on the way to Windows; anything else
|
|
39
|
+
raises `PortablePathError` (`FlatPathError` in `to_flat_path`). 0.3.1 re-read a
|
|
40
|
+
`PurePath` with the flavor of `platform` (or of the running system) in `to_lv_path`,
|
|
41
|
+
`to_flat_path`, `to_os_path`, `path_kind` and, on POSIX, `from_portable_path`, producing a different path for anchored
|
|
42
|
+
ones, and `from_portable_path` raised `TypeError` for a `PurePath` on Windows. The
|
|
43
|
+
annotations of `to_os_path`, `path_kind` and `from_portable_path` now include
|
|
44
|
+
`PurePath`, and that of `to_flat_path` includes `None`.
|
|
45
|
+
- `platform` is checked before anything else in every function: an unknown name raises
|
|
46
|
+
`ValueError` and a value that is not a `str`, `Platform` or `None` raises `TypeError`
|
|
47
|
+
(0.3.1 raised `AttributeError`), even when the path is empty or the bytes are malformed.
|
|
48
|
+
In 0.3.1, `path_kind("", platform="bogus")` returned `NOT_A_PATH`, `to_lv_path` and
|
|
49
|
+
`to_portable_path` returned `""`, `to_os_path` and `from_portable_path` raised
|
|
50
|
+
`NotAPathError` and `from_flat_path` raised `FlatPathError` for bad bytes.
|
|
51
|
+
- Arguments of the wrong type raise `TypeError` with a short message. 0.3.1 returned
|
|
52
|
+
`'5'` for `to_portable_path(5)` and `"b'x'"` for `to_portable_path(b"x")`, raised
|
|
53
|
+
`AttributeError` for `to_lv_path(5)` and `to_flat_path(5)`, and raised `FlatPathError`
|
|
54
|
+
for `parse_flat_path` given a short `str`.
|
|
55
|
+
- `FlatPath` checks its fields when built: a `bool` or non-integer path type and a
|
|
56
|
+
non-`str` component raise `TypeError` (0.3.1 accepted `FlatPath(0, "ab")`); a non-ASCII
|
|
57
|
+
or over-long component raises `FlatPathError` at once (0.3.1 raised it later, in
|
|
58
|
+
`to_bytes`). The path type is stored as a plain `int` (0.3.1 kept an `IntEnum` member as
|
|
59
|
+
given) and the components as a tuple. `build_flat_path` refuses a `str` as its
|
|
60
|
+
components with `TypeError` (0.3.1 split it into one-character components). A pickle
|
|
61
|
+
written by 0.3.1 loads with its fields normalised the same way.
|
|
62
|
+
- Non-ASCII flattened bytes raise `FlatPathError` instead of `UnicodeDecodeError`.
|
|
63
|
+
`parse_flat_path`, `FlatPath.from_bytes` and `from_flat_path` read the raw bytes of any
|
|
64
|
+
object with the buffer protocol (`bytes`, `bytearray`, `memoryview`, `array`, `mmap`)
|
|
65
|
+
and are typed for `bytes | bytearray | memoryview`. 0.3.1 read `bytes` and
|
|
66
|
+
`bytearray` only: a `memoryview` or `array` holding a component raised
|
|
67
|
+
`AttributeError`, and a wide `array` was measured in items.
|
|
68
|
+
- Error messages quote at most 40 characters of a value and several are reworded; the
|
|
69
|
+
exception types are unchanged except where listed here. The public classes
|
|
70
|
+
(`FlatPath`, `FlatPathType`, `PathKind`, `Platform` and the three exceptions) report
|
|
71
|
+
their module as `lvpath`, so pickles name `lvpath.<class>`; pickles made by 0.3.1 still
|
|
72
|
+
load.
|
|
73
|
+
- Command line: a usage mistake still exits 2, now with lines of at most 200 characters;
|
|
74
|
+
a refused value prints one bounded line and exits 1; a closed output pipe exits 1
|
|
75
|
+
quietly; invalid hex no longer echoes the parser's detail; `lvpath encode ''` prints the
|
|
76
|
+
not-a-path bytes and `lvpath decode` of them is refused. A POSIX argument that is not
|
|
77
|
+
valid UTF-8 is written back as its original bytes (0.3.1 stopped with a
|
|
78
|
+
`UnicodeEncodeError` traceback); a lone surrogate UTF-8 cannot write at all (possible
|
|
79
|
+
in Windows arguments) is refused in one line with status 1; a missing standard stream
|
|
80
|
+
no longer raises.
|
|
81
|
+
- A `str` subclass is read through its plain text: an overridden `__eq__` or `__len__`
|
|
82
|
+
no longer changes a result or slips past the component limits.
|
|
83
|
+
|
|
84
|
+
### Added
|
|
85
|
+
|
|
86
|
+
- `python -m lvpath`.
|
|
87
|
+
- `FlatPathType.NOT_A_PATH` and `FlatPathType.UNC`.
|
|
88
|
+
- `GUIDE.md` with the rules, the errors table, the ground truth and upgrade notes.
|
|
89
|
+
- Docstring examples for every public name, run as doctests.
|
|
90
|
+
|
|
91
|
+
## [0.3.1]
|
|
92
|
+
|
|
93
|
+
- The LabVIEW 2026 path fixture no longer carries source lines copied from NI files: each
|
|
94
|
+
row keeps only the path value, its expected renderings, and where it was found (file and
|
|
95
|
+
setting). The sdist is limited to the package, the tests and the docs.
|
|
96
|
+
|
|
97
|
+
## [0.3.0]
|
|
98
|
+
|
|
99
|
+
- Added the portable path form LabVIEW writes into configuration and project
|
|
100
|
+
files. `from_portable_path` reads `/C/DIR1/DIR2` as `C:\DIR1\DIR2`,
|
|
101
|
+
`//server/share/dir` as a UNC path and `../a/b` as a relative path;
|
|
102
|
+
`to_portable_path` writes them back, keeping the drive letter case. The empty value is `<Not A Path>`.
|
|
103
|
+
- `PortablePathError` reports a value with no faithful counterpart instead of
|
|
104
|
+
rewriting it into another path: a POSIX absolute path read as Windows, a
|
|
105
|
+
drive-relative `C:file`, a rooted Windows path without a drive, a UNC path
|
|
106
|
+
without a share and a `\\?\` device path.
|
|
107
|
+
- The `lvpath` command line gains `to-native` and `to-labview`, and its help lists
|
|
108
|
+
runnable examples for every subcommand.
|
|
109
|
+
- The test suite carries a verbatim excerpt of path values from files shipped with
|
|
110
|
+
LabVIEW 2026 and checks every value in both directions and through a round trip.
|
|
111
|
+
- The README no longer implies that `to_os_path` translates `/C/foo`; it documents
|
|
112
|
+
the portable form, its rules and its one ambiguity.
|
|
113
|
+
|
|
114
|
+
## [0.2.0]
|
|
115
|
+
|
|
116
|
+
- Added the binary flattened path form (`Flatten To String` `PTH0`). `FlatPath` is
|
|
117
|
+
a typed, frozen result with `to_bytes` and `from_bytes`; `parse_flat_path` and
|
|
118
|
+
`build_flat_path` are the codec entry points. The NI `C:\File` example round-trips
|
|
119
|
+
byte for byte in both directions.
|
|
120
|
+
- `to_flat_path` and `from_flat_path` bridge the flattened form to and from
|
|
121
|
+
`pathlib.PurePath` on a chosen platform flavor.
|
|
122
|
+
- `FlatPathType` exposes the two documented path type codes (absolute `0`, relative
|
|
123
|
+
`1`). UNC and not-a-path codes are undocumented, so they are not guessed: the
|
|
124
|
+
codec still round-trips their raw bytes, while the PurePath bridge refuses an
|
|
125
|
+
un-interpretable type code with `FlatPathError`.
|
|
126
|
+
- Added an `lvpath` command line with `decode` and `encode` subcommands and
|
|
127
|
+
`--version`.
|
|
128
|
+
|
|
129
|
+
## [0.1.0]
|
|
130
|
+
|
|
131
|
+
- First release.
|
|
132
|
+
- `to_os_path` parses a LabVIEW path string into a `PurePath` of the Windows or
|
|
133
|
+
POSIX flavor; `to_lv_path` serializes an OS path back into a LabVIEW string.
|
|
134
|
+
- `path_kind` and `PathKind` detect absolute, relative and not-a-path values;
|
|
135
|
+
the empty string is the not-a-path value on every platform.
|
|
136
|
+
- `NotAPathError` is raised when the not-a-path value is converted to an OS path.
|
|
137
|
+
- Covers the textual `Path To String` / `String To Path` conventions: Windows
|
|
138
|
+
drive and UNC anchors, POSIX roots, lenient forward slashes, and clean
|
|
139
|
+
cross-platform conversion of relative path objects. Classic Mac OS colon paths
|
|
140
|
+
and the binary flatten path type are out of scope.
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
# Contributing
|
|
2
|
-
|
|
3
|
-
Thanks for taking the time. This project keeps a small, predictable shape.
|
|
4
|
-
|
|
5
|
-
## Setup
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
pip install -r requirements-dev.txt
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Before you open a pull request
|
|
12
|
-
|
|
13
|
-
- Keep public API in `src/lvpath/__init__.py`; internals live in `_`-prefixed modules.
|
|
14
|
-
- Add a test for the behaviour you change. Tests inject time, disk and network; they
|
|
15
|
-
never touch the real thing.
|
|
16
|
-
- Run `scripts/check.ps1` (format, lint, types, tests) and make sure it passes.
|
|
17
|
-
- One logical change per commit, imperative subject line.
|
|
18
|
-
|
|
19
|
-
Open an issue first if the change is large or shifts the public API.
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for taking the time. This project keeps a small, predictable shape.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
pip install -r requirements-dev.txt
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Before you open a pull request
|
|
12
|
+
|
|
13
|
+
- Keep public API in `src/lvpath/__init__.py`; internals live in `_`-prefixed modules.
|
|
14
|
+
- Add a test for the behaviour you change. Tests inject time, disk and network; they
|
|
15
|
+
never touch the real thing.
|
|
16
|
+
- Run `scripts/check.ps1` (format, lint, types, tests) and make sure it passes.
|
|
17
|
+
- One logical change per commit, imperative subject line.
|
|
18
|
+
|
|
19
|
+
Open an issue first if the change is large or shifts the public API.
|
lvpath-1.0.0/GUIDE.md
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
# lvpath guide
|
|
2
|
+
|
|
3
|
+
LabVIEW keeps a path in three forms. lvpath converts each of them to and from
|
|
4
|
+
`pathlib.PurePath` without touching the file system:
|
|
5
|
+
|
|
6
|
+
| Form | Where LabVIEW uses it | lvpath |
|
|
7
|
+
| --- | --- | --- |
|
|
8
|
+
| Portable text, `/C/DIR1/DIR2` | path values in `.ini` and `.lvproj` files | `from_portable_path`, `to_portable_path` |
|
|
9
|
+
| Native text, `C:\DIR1\DIR2` | `Path To String`, `String To Path` | `to_os_path`, `to_lv_path`, `path_kind` |
|
|
10
|
+
| Flattened bytes, `PTH0...` | `Flatten To String`, VI files, datalogs | `from_flat_path`, `to_flat_path`, `FlatPath` |
|
|
11
|
+
|
|
12
|
+
## The platform argument
|
|
13
|
+
|
|
14
|
+
Every conversion takes `platform`: `"windows"` or `"posix"` in any letter case, a
|
|
15
|
+
`Platform` member, or `None` for the system running the code. A `str` argument is
|
|
16
|
+
parsed with that flavor. A `PurePath` argument keeps its own flavor; when `platform`
|
|
17
|
+
names the other flavor, only a relative path may cross, and a component holding a
|
|
18
|
+
backslash or a colon may not cross to Windows.
|
|
19
|
+
|
|
20
|
+
```pycon
|
|
21
|
+
>>> from pathlib import PurePosixPath, PureWindowsPath
|
|
22
|
+
>>> from lvpath import Platform, to_lv_path
|
|
23
|
+
>>> to_lv_path(PureWindowsPath("reports\\q1.txt"), platform="posix")
|
|
24
|
+
'reports/q1.txt'
|
|
25
|
+
>>> to_lv_path(PureWindowsPath("C:/x"), platform=Platform.POSIX)
|
|
26
|
+
Traceback (most recent call last):
|
|
27
|
+
...
|
|
28
|
+
lvpath.PortablePathError: cannot carry the anchored path 'C:\\x' to the PurePosixPath flavor
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Portable text form
|
|
33
|
+
|
|
34
|
+
When LabVIEW writes a path value into a configuration or project file it uses a
|
|
35
|
+
platform-independent text: a Windows drive becomes a leading one-letter component, every
|
|
36
|
+
separator is `/`, a UNC share keeps its leading `//` and the empty string is
|
|
37
|
+
`<Not A Path>`.
|
|
38
|
+
|
|
39
|
+
| Stored value | `platform="windows"` | `platform="posix"` |
|
|
40
|
+
| --- | --- | --- |
|
|
41
|
+
| `/C/Program Files (x86)/Arduino` | `C:\Program Files (x86)\Arduino` | unchanged |
|
|
42
|
+
| `/c/ni-rt/startup` | `c:\ni-rt\startup` | unchanged |
|
|
43
|
+
| `/D` | `D:\` | unchanged |
|
|
44
|
+
| `//server/share/dir` | `\\server\share\dir` | unchanged |
|
|
45
|
+
| `../builds/Main Application` | `..\builds\Main Application` | unchanged |
|
|
46
|
+
| `/home/lvuser/natinst/bin` | `PortablePathError` | unchanged |
|
|
47
|
+
| empty | `NotAPathError` | `NotAPathError` |
|
|
48
|
+
|
|
49
|
+
```pycon
|
|
50
|
+
>>> from lvpath import from_portable_path, to_portable_path
|
|
51
|
+
>>> from_portable_path("/D", platform="windows")
|
|
52
|
+
PureWindowsPath('D:/')
|
|
53
|
+
>>> to_portable_path("\\\\server\\share\\dir", platform="windows")
|
|
54
|
+
'//server/share/dir'
|
|
55
|
+
>>> to_portable_path("C:file", platform="windows")
|
|
56
|
+
Traceback (most recent call last):
|
|
57
|
+
...
|
|
58
|
+
lvpath.PortablePathError: 'C:file' is drive-relative and has no portable form
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
- The drive letter keeps its case, so a value in the normal form LabVIEW writes (no
|
|
63
|
+
trailing slash, repeated separator or `.` part) round-trips exactly.
|
|
64
|
+
- A value already in native Windows form (`C:\NI Installers`), which some NI files
|
|
65
|
+
store, is accepted as is when reading on Windows.
|
|
66
|
+
- On POSIX the stored form is already native and is parsed unchanged, so `/C/x` is a
|
|
67
|
+
drive on Windows and a directory on POSIX. Pick `platform` for the system that will
|
|
68
|
+
use the path.
|
|
69
|
+
- Refused with `PortablePathError`: a POSIX absolute path read as Windows, a malformed
|
|
70
|
+
drive (`/C:/x`), a drive-relative `C:file`, a rooted path without a drive (`\dir`),
|
|
71
|
+
a UNC path without a share and the `\\?\` and `\\.\` device forms.
|
|
72
|
+
- `pathlib` normalises the text: repeated separators collapse, a trailing slash and
|
|
73
|
+
`.` parts are dropped, and a backslash read on Windows is a separator.
|
|
74
|
+
- An empty `PurePath` is pathlib's current directory and writes as `"."`; `None` and
|
|
75
|
+
`""` write as `""`.
|
|
76
|
+
|
|
77
|
+
The table rows are checked against values found in files shipped with LabVIEW 2026
|
|
78
|
+
(`tests/fixtures/labview2026_paths.json` records each value with its file and setting,
|
|
79
|
+
not the file text). No shipped file holds a bare drive or a UNC value; those rows are
|
|
80
|
+
covered by tests written by hand that follow the same convention.
|
|
81
|
+
|
|
82
|
+
## Native text form
|
|
83
|
+
|
|
84
|
+
`to_os_path` and `path_kind` read the text of a host platform, `to_lv_path` writes it.
|
|
85
|
+
On Windows forward slashes are accepted, and only a drive with a root or a UNC share is
|
|
86
|
+
absolute, so `C:file` and `\dir` count as relative, as `pathlib` decides.
|
|
87
|
+
|
|
88
|
+
```pycon
|
|
89
|
+
>>> from lvpath import NotAPathError, PathKind, path_kind, to_os_path
|
|
90
|
+
>>> path_kind("C:file", platform="windows")
|
|
91
|
+
<PathKind.RELATIVE: 'relative'>
|
|
92
|
+
>>> to_os_path("/C/foo", platform="windows")
|
|
93
|
+
PureWindowsPath('/C/foo')
|
|
94
|
+
>>> try:
|
|
95
|
+
... to_os_path("", platform="posix")
|
|
96
|
+
... except NotAPathError as error:
|
|
97
|
+
... print(error)
|
|
98
|
+
LabVIEW not-a-path has no OS path
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Read stored values with `from_portable_path`: `to_os_path` keeps `/C/foo` as the rooted
|
|
103
|
+
Windows path `\C\foo`.
|
|
104
|
+
|
|
105
|
+
## Flattened form
|
|
106
|
+
|
|
107
|
+
`Flatten To String` writes a path as `PTH0`, a u32 byte count of the rest, a u16 path
|
|
108
|
+
type, a u16 component count and one length-prefixed ASCII string per component, all
|
|
109
|
+
big-endian. `FlatPath`, `parse_flat_path` and `build_flat_path` read and write that
|
|
110
|
+
container exactly and keep any path type as a number.
|
|
111
|
+
|
|
112
|
+
```pycon
|
|
113
|
+
>>> from lvpath import FlatPath, build_flat_path, from_flat_path, parse_flat_path, to_flat_path
|
|
114
|
+
>>> parse_flat_path(build_flat_path(1, ["", "", "NI_MDF.lvlib"]))
|
|
115
|
+
FlatPath(path_type=1, components=('', '', 'NI_MDF.lvlib'))
|
|
116
|
+
>>> from_flat_path(build_flat_path(1, ["", "", "NI_MDF.lvlib"]), platform="windows")
|
|
117
|
+
PureWindowsPath('../../NI_MDF.lvlib')
|
|
118
|
+
>>> from_flat_path(build_flat_path(0, []), platform="posix")
|
|
119
|
+
PurePosixPath('/')
|
|
120
|
+
>>> from_flat_path(build_flat_path(0, ["<vilib>", "Utility"]), platform="posix")
|
|
121
|
+
Traceback (most recent call last):
|
|
122
|
+
...
|
|
123
|
+
lvpath.FlatPathError: symbolic path prefix '<vilib>' has no PurePath meaning
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
The path type codes are those LabVIEW's `cintools/extcode.h` lists in order (`fAbsPath`,
|
|
128
|
+
`fRelPath`, `fNotAPath`, `fUNCPath`), exposed as `FlatPathType`, and
|
|
129
|
+
`from_flat_path` and `to_flat_path` interpret three of them:
|
|
130
|
+
|
|
131
|
+
- `0`, absolute (`ABSOLUTE`). On Windows the first component is the drive letter
|
|
132
|
+
without its colon; on POSIX the components follow the root, and no component at all
|
|
133
|
+
is `/`. That empty absolute path (LabVIEW's empty path, common in VI files) has no
|
|
134
|
+
Windows `PurePath` and raises `FlatPathError` there.
|
|
135
|
+
- `1`, relative (`RELATIVE`). No component at all is `.`.
|
|
136
|
+
- In both, an empty component means one level up, `..` in text.
|
|
137
|
+
- `2`, `<Not A Path>` (`NOT_A_PATH`), with no component. `to_flat_path("")` and
|
|
138
|
+
`to_flat_path(None)` write it; `from_flat_path` raises `NotAPathError` for it.
|
|
139
|
+
|
|
140
|
+
Everything else raises `FlatPathError` in the bridge: `3`, UNC (`UNC`; no UNC record
|
|
141
|
+
exists in the LabVIEW install to confirm its component layout, so it is not guessed),
|
|
142
|
+
any other code, a symbolic first component such as `<vilib>`, a first Windows component
|
|
143
|
+
that is not one letter, a literal `.` or `..` component, a component holding `/` (or `\`
|
|
144
|
+
or `:` on Windows), UNC and driveless rooted Windows paths, drive-relative paths and
|
|
145
|
+
POSIX paths starting with `//`. Components are ASCII, at most 255 characters, and at
|
|
146
|
+
most 65535 of them.
|
|
147
|
+
|
|
148
|
+
### Ground truth for the flattened form
|
|
149
|
+
|
|
150
|
+
- NI's flattened-data page gives `C:\File` as
|
|
151
|
+
`5054 4830 0000 000B 0000 0002 0143 0466 696C 65` and names type `0` only. Its bytes
|
|
152
|
+
spell `file` in lower case. `tests/test_sources_truth.py` reads the example from a
|
|
153
|
+
copy fetched by `scripts/fetch_sources.py` (not committed; `MANIFEST.json` keeps the
|
|
154
|
+
URL, date and SHA-256).
|
|
155
|
+
- `scripts/scan_labview_paths.py` walked a LabVIEW 2026 install on 2026-10-15, skipping
|
|
156
|
+
files over 50 MB (`LabVIEW.exe`, `resource/libcef.dll` and the object cache
|
|
157
|
+
`VIObjCache/26.0.0r0/objFileDB.vidb`, whose records include split, corrupted
|
|
158
|
+
fragments), and found
|
|
159
|
+
321,686 records of type `0`, 27,879 of type `1` and one of type `2`. Of the 24,024
|
|
160
|
+
relative links that start with empty components, 21,765 name an existing file when
|
|
161
|
+
each empty component is read as one level up from the file holding the link; no
|
|
162
|
+
record holds a literal `..`. The one type `2` record, `PTH0 00000004 0002 0000`, is
|
|
163
|
+
exactly what `to_flat_path("")` writes. Eleven chosen records, with file and offset,
|
|
164
|
+
are in `tests/fixtures/labview2026_flat.json`.
|
|
165
|
+
- `cintools/extcode.h` of LabVIEW 2026 lists the path type codes in order: absolute,
|
|
166
|
+
relative, not-a-path, UNC.
|
|
167
|
+
|
|
168
|
+
## Errors
|
|
169
|
+
|
|
170
|
+
| Exception | Base | Raised for |
|
|
171
|
+
| --- | --- | --- |
|
|
172
|
+
| `NotAPathError` | `ValueError` | `<Not A Path>` (an empty string, or flattened type `2`) read as an OS path |
|
|
173
|
+
| `PortablePathError` | `ValueError` | a value with no faithful counterpart in the portable or native form |
|
|
174
|
+
| `FlatPathError` | `ValueError` | malformed `PTH0` bytes, bad components, a path the bridge cannot represent |
|
|
175
|
+
| `ValueError` | | an unknown `platform` name |
|
|
176
|
+
| `TypeError` | | an argument of the wrong type (a path that is not `str` or `PurePath`, bytes that are not bytes-like, a non-integer path type) |
|
|
177
|
+
|
|
178
|
+
A message quotes at most 40 characters of any value and states the full length of a
|
|
179
|
+
longer one. The public classes report their module as `lvpath`.
|
|
180
|
+
|
|
181
|
+
```pycon
|
|
182
|
+
>>> from lvpath import FlatPathError, PortablePathError
|
|
183
|
+
>>> try:
|
|
184
|
+
... to_portable_path("C:" + "x" * 1000, platform="windows")
|
|
185
|
+
... except PortablePathError as error:
|
|
186
|
+
... print(error)
|
|
187
|
+
'C:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' (first 40 of 1002 characters) is drive-relative and has no portable form
|
|
188
|
+
>>> issubclass(FlatPathError, ValueError)
|
|
189
|
+
True
|
|
190
|
+
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Command line
|
|
194
|
+
|
|
195
|
+
```console
|
|
196
|
+
$ lvpath to-native --platform windows //server/share/dir
|
|
197
|
+
\\server\share\dir
|
|
198
|
+
$ lvpath to-labview --platform posix ''
|
|
199
|
+
|
|
200
|
+
$ lvpath decode --platform posix '50544830 00000007 0001 0002 00 0161'
|
|
201
|
+
../a
|
|
202
|
+
$ lvpath to-native --platform windows /home/lvuser
|
|
203
|
+
lvpath: '/home/lvuser' is a POSIX absolute path with no Windows equivalent
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Output is UTF-8, and a POSIX argument that is not valid UTF-8 is written back as its
|
|
207
|
+
original bytes. A refused value prints one line on standard error and exits with
|
|
208
|
+
status 1; a usage mistake prints the usage and one line and exits with status 2; a
|
|
209
|
+
closed output pipe exits with status 1 quietly. A value starting with `-` goes after
|
|
210
|
+
`--`. Under Git Bash on Windows set `MSYS_NO_PATHCONV=1` so `/C/x` reaches lvpath
|
|
211
|
+
unchanged.
|
|
212
|
+
|
|
213
|
+
## Upgrading from 0.3
|
|
214
|
+
|
|
215
|
+
The public names and parameters are the same; `python -m lvpath`,
|
|
216
|
+
`FlatPathType.NOT_A_PATH` and `FlatPathType.UNC` are new. Behaviour that changed (the
|
|
217
|
+
same list as CHANGELOG 1.0.0):
|
|
218
|
+
|
|
219
|
+
- An empty flattened component now decodes as `..` and `..` encodes as an empty
|
|
220
|
+
component, which is how LabVIEW 2026 stores relative links (21,765 links in its own
|
|
221
|
+
files resolve that way). 0.3.1 dropped the empty components, so
|
|
222
|
+
`('', '', 'NI_MDF.lvlib')` decoded as `NI_MDF.lvlib`, and wrote `..` as two dots.
|
|
223
|
+
- `<Not A Path>` in the flattened form is path type 2 with no component, the code
|
|
224
|
+
LabVIEW's `cintools/extcode.h` gives it and the record LabVIEW 2026 stores in
|
|
225
|
+
`resource/labview.rsc`. `to_flat_path("")` and `to_flat_path(None)` now write it (0.3.1
|
|
226
|
+
wrote `""` as an empty relative path, which decodes as `.`, and raised
|
|
227
|
+
`AttributeError` for `None`), and `from_flat_path` raises `NotAPathError` for it (0.3.1:
|
|
228
|
+
`FlatPathError`). `FlatPathType` gains `NOT_A_PATH` (2) and `UNC` (3); a UNC flattened
|
|
229
|
+
path is still refused with `FlatPathError`.
|
|
230
|
+
- `from_flat_path` refuses with `FlatPathError` what 0.3.1 misread: a symbolic
|
|
231
|
+
`<vilib>`-style first component of an absolute path, a first Windows component that is
|
|
232
|
+
not one drive letter (0.3.1 produced `usr:\lib`), literal `.` and `..` components, and
|
|
233
|
+
components holding `/` (or `\` or `:` on Windows).
|
|
234
|
+
- `to_flat_path` refuses a POSIX path starting with `//` (0.3.1 dropped one slash) and a
|
|
235
|
+
rooted Windows path without a drive such as `\usr\x` (0.3.1 wrote it as a relative path
|
|
236
|
+
whose first component was a backslash).
|
|
237
|
+
- One flavor rule for `PurePath` arguments in every function: a `PurePath` keeps its own
|
|
238
|
+
flavor unless `platform` names the other one, and then only a relative path may cross,
|
|
239
|
+
with no backslash or colon inside a component on the way to Windows; anything else
|
|
240
|
+
raises `PortablePathError` (`FlatPathError` in `to_flat_path`). 0.3.1 re-read a
|
|
241
|
+
`PurePath` with the flavor of `platform` (or of the running system) in `to_lv_path`,
|
|
242
|
+
`to_flat_path`, `to_os_path`, `path_kind` and, on POSIX, `from_portable_path`, producing a different path for anchored
|
|
243
|
+
ones, and `from_portable_path` raised `TypeError` for a `PurePath` on Windows. The
|
|
244
|
+
annotations of `to_os_path`, `path_kind` and `from_portable_path` now include
|
|
245
|
+
`PurePath`, and that of `to_flat_path` includes `None`.
|
|
246
|
+
- `platform` is checked before anything else in every function: an unknown name raises
|
|
247
|
+
`ValueError` and a value that is not a `str`, `Platform` or `None` raises `TypeError`
|
|
248
|
+
(0.3.1 raised `AttributeError`), even when the path is empty or the bytes are malformed.
|
|
249
|
+
In 0.3.1, `path_kind("", platform="bogus")` returned `NOT_A_PATH`, `to_lv_path` and
|
|
250
|
+
`to_portable_path` returned `""`, `to_os_path` and `from_portable_path` raised
|
|
251
|
+
`NotAPathError` and `from_flat_path` raised `FlatPathError` for bad bytes.
|
|
252
|
+
- Arguments of the wrong type raise `TypeError` with a short message. 0.3.1 returned
|
|
253
|
+
`'5'` for `to_portable_path(5)` and `"b'x'"` for `to_portable_path(b"x")`, raised
|
|
254
|
+
`AttributeError` for `to_lv_path(5)` and `to_flat_path(5)`, and raised `FlatPathError`
|
|
255
|
+
for `parse_flat_path` given a short `str`.
|
|
256
|
+
- `FlatPath` checks its fields when built: a `bool` or non-integer path type and a
|
|
257
|
+
non-`str` component raise `TypeError` (0.3.1 accepted `FlatPath(0, "ab")`); a non-ASCII
|
|
258
|
+
or over-long component raises `FlatPathError` at once (0.3.1 raised it later, in
|
|
259
|
+
`to_bytes`). The path type is stored as a plain `int` (0.3.1 kept an `IntEnum` member as
|
|
260
|
+
given) and the components as a tuple. `build_flat_path` refuses a `str` as its
|
|
261
|
+
components with `TypeError` (0.3.1 split it into one-character components). A pickle
|
|
262
|
+
written by 0.3.1 loads with its fields normalised the same way.
|
|
263
|
+
- Non-ASCII flattened bytes raise `FlatPathError` instead of `UnicodeDecodeError`.
|
|
264
|
+
`parse_flat_path`, `FlatPath.from_bytes` and `from_flat_path` read the raw bytes of any
|
|
265
|
+
object with the buffer protocol (`bytes`, `bytearray`, `memoryview`, `array`, `mmap`)
|
|
266
|
+
and are typed for `bytes | bytearray | memoryview`. 0.3.1 read `bytes` and
|
|
267
|
+
`bytearray` only: a `memoryview` or `array` holding a component raised
|
|
268
|
+
`AttributeError`, and a wide `array` was measured in items.
|
|
269
|
+
- Error messages quote at most 40 characters of a value and several are reworded; the
|
|
270
|
+
exception types are unchanged except where listed here. The public classes
|
|
271
|
+
(`FlatPath`, `FlatPathType`, `PathKind`, `Platform` and the three exceptions) report
|
|
272
|
+
their module as `lvpath`, so pickles name `lvpath.<class>`; pickles made by 0.3.1 still
|
|
273
|
+
load.
|
|
274
|
+
- Command line: a usage mistake still exits 2, now with lines of at most 200 characters;
|
|
275
|
+
a refused value prints one bounded line and exits 1; a closed output pipe exits 1
|
|
276
|
+
quietly; invalid hex no longer echoes the parser's detail; `lvpath encode ''` prints the
|
|
277
|
+
not-a-path bytes and `lvpath decode` of them is refused. A POSIX argument that is not
|
|
278
|
+
valid UTF-8 is written back as its original bytes (0.3.1 stopped with a
|
|
279
|
+
`UnicodeEncodeError` traceback); a lone surrogate UTF-8 cannot write at all (possible
|
|
280
|
+
in Windows arguments) is refused in one line with status 1; a missing standard stream
|
|
281
|
+
no longer raises.
|
|
282
|
+
- A `str` subclass is read through its plain text: an overridden `__eq__` or `__len__`
|
|
283
|
+
no longer changes a result or slips past the component limits.
|
|
284
|
+
|
|
285
|
+
## What it does not do
|
|
286
|
+
|
|
287
|
+
- No file system access, no symbolic links, no `.`/`..` resolution beyond `pathlib`.
|
|
288
|
+
- No classic Mac OS colon paths.
|
|
289
|
+
- No expansion of symbolic prefixes such as `<vilib>` and no resolution of a relative
|
|
290
|
+
value against the file it came from.
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Javier Lianes
|
|
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.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Javier Lianes
|
|
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.
|
lvpath-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: lvpath
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Convert LabVIEW path strings, the portable /C/DIR form of config and project files, and the flattened PTH0 form to and from native paths.
|
|
5
|
+
Project-URL: Homepage, https://lianes8studio.com
|
|
6
|
+
Project-URL: Source, https://github.com/JaviLianes8/lvpath
|
|
7
|
+
Project-URL: Issues, https://github.com/JaviLianes8/lvpath/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/JaviLianes8/lvpath/blob/main/CHANGELOG.md
|
|
9
|
+
Project-URL: LinkedIn, https://www.linkedin.com/in/jlianes/
|
|
10
|
+
Project-URL: Funding, https://buymeacoffee.com/jlianesglrs
|
|
11
|
+
Author-email: Javier Lianes <javier@lianes8studio.com>
|
|
12
|
+
License-Expression: MIT
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Keywords: flatten,ini,labview,lvproj,ni,path,pathlib,portable,pth0
|
|
15
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: Intended Audience :: Science/Research
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
26
|
+
Classifier: Topic :: Scientific/Engineering
|
|
27
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
28
|
+
Classifier: Typing :: Typed
|
|
29
|
+
Requires-Python: >=3.10
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: build; extra == 'dev'
|
|
32
|
+
Requires-Dist: mypy; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
34
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
35
|
+
Requires-Dist: twine; extra == 'dev'
|
|
36
|
+
Description-Content-Type: text/markdown
|
|
37
|
+
|
|
38
|
+
# lvpath
|
|
39
|
+
|
|
40
|
+
Convert LabVIEW path values to and from Python `pathlib` paths, in all three forms
|
|
41
|
+
LabVIEW uses: the portable text it writes into configuration and project files
|
|
42
|
+
(`/C/DIR1/DIR2`), the native text of `Path To String`, and the flattened `PTH0` bytes
|
|
43
|
+
of `Flatten To String`. Typed, no dependencies, Python 3.10 to 3.14.
|
|
44
|
+
|
|
45
|
+
## Install
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
pip install lvpath
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Quick start
|
|
52
|
+
|
|
53
|
+
Read a path value stored in an `.ini` or `.lvproj` file, and write one back:
|
|
54
|
+
|
|
55
|
+
```pycon
|
|
56
|
+
>>> from lvpath import from_portable_path, to_portable_path
|
|
57
|
+
>>> from_portable_path("/C/Program Files (x86)/Arduino", platform="windows")
|
|
58
|
+
PureWindowsPath('C:/Program Files (x86)/Arduino')
|
|
59
|
+
>>> from_portable_path("../builds/Main Application", platform="windows")
|
|
60
|
+
PureWindowsPath('../builds/Main Application')
|
|
61
|
+
>>> to_portable_path("C:/DIR1/DIR2", platform="windows")
|
|
62
|
+
'/C/DIR1/DIR2'
|
|
63
|
+
>>> to_portable_path(None)
|
|
64
|
+
''
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Decode the flattened bytes of a LabVIEW path, such as NI's `C:\File` example:
|
|
69
|
+
|
|
70
|
+
```pycon
|
|
71
|
+
>>> from lvpath import from_flat_path, parse_flat_path, to_flat_path
|
|
72
|
+
>>> golden = bytes.fromhex("505448300000000b0000000201430466696c65")
|
|
73
|
+
>>> parse_flat_path(golden)
|
|
74
|
+
FlatPath(path_type=0, components=('C', 'file'))
|
|
75
|
+
>>> from_flat_path(golden, platform="windows")
|
|
76
|
+
PureWindowsPath('C:/file')
|
|
77
|
+
>>> to_flat_path("C:/file", platform="windows") == golden
|
|
78
|
+
True
|
|
79
|
+
>>> from_flat_path(to_flat_path("../lib/x.vi", platform="posix"), platform="posix")
|
|
80
|
+
PurePosixPath('../lib/x.vi')
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Work with the native text form and LabVIEW's `<Not A Path>` (the empty string):
|
|
85
|
+
|
|
86
|
+
```pycon
|
|
87
|
+
>>> from lvpath import path_kind, to_lv_path, to_os_path
|
|
88
|
+
>>> to_os_path("C:\\Users\\test\\data.txt", platform="windows")
|
|
89
|
+
PureWindowsPath('C:/Users/test/data.txt')
|
|
90
|
+
>>> to_lv_path("logs/run.txt", platform="windows")
|
|
91
|
+
'logs\\run.txt'
|
|
92
|
+
>>> path_kind("", platform="posix")
|
|
93
|
+
<PathKind.NOT_A_PATH: 'not_a_path'>
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Every `platform` argument takes `"windows"`, `"posix"`, a `Platform` member, or `None`
|
|
98
|
+
for the system running the code. Values with no faithful counterpart raise a typed
|
|
99
|
+
error (`PortablePathError`, `FlatPathError`, `NotAPathError`) instead of being turned
|
|
100
|
+
into a different path.
|
|
101
|
+
|
|
102
|
+
## Command line
|
|
103
|
+
|
|
104
|
+
```console
|
|
105
|
+
$ lvpath to-native --platform windows '/C/Program Files (x86)/Arduino'
|
|
106
|
+
C:\Program Files (x86)\Arduino
|
|
107
|
+
$ lvpath to-labview --platform windows 'C:\DIR1\DIR2'
|
|
108
|
+
/C/DIR1/DIR2
|
|
109
|
+
$ lvpath decode --platform windows 505448300000000b0000000201430466696c65
|
|
110
|
+
C:\file
|
|
111
|
+
$ lvpath encode --platform posix ../lib/x.vi
|
|
112
|
+
505448300000000e0001000300036c696204782e7669
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
`python -m lvpath` runs the same command. Refused values exit with status 1, usage
|
|
116
|
+
mistakes with status 2. Run `lvpath --help` for every option.
|
|
117
|
+
|
|
118
|
+
## Why
|
|
119
|
+
|
|
120
|
+
LabVIEW writes one path in different forms depending on where it goes, and none of
|
|
121
|
+
them reads correctly with plain string handling: `/C/DIR1/DIR2` names the wrong file on
|
|
122
|
+
Windows, a native string means something only with the platform it was written on,
|
|
123
|
+
and the flattened form needs the `PTH0` layout. `pathlib`'s `PureWindowsPath` and
|
|
124
|
+
`PurePosixPath` already handle foreign-platform paths with no file access, so lvpath is
|
|
125
|
+
a thin layer on top of them that adds only the LabVIEW part: the portable drive and UNC
|
|
126
|
+
form, `<Not A Path>`, and the flattened container, including the rule that an empty
|
|
127
|
+
flattened component means one level up.
|
|
128
|
+
|
|
129
|
+
The conversions are checked against path values in files shipped with LabVIEW 2026,
|
|
130
|
+
against flattened paths LabVIEW 2026 stored in its own installed files, and against
|
|
131
|
+
the example on NI's public flattened-data page.
|
|
132
|
+
|
|
133
|
+
## Documentation
|
|
134
|
+
|
|
135
|
+
- [Guide](https://github.com/JaviLianes8/lvpath/blob/main/GUIDE.md): every rule, the
|
|
136
|
+
errors, the command line and upgrading from 0.3.
|
|
137
|
+
- [Changelog](https://github.com/JaviLianes8/lvpath/blob/main/CHANGELOG.md)
|
|
138
|
+
|
|
139
|
+
## License
|
|
140
|
+
|
|
141
|
+
MIT. See [LICENSE](https://github.com/JaviLianes8/lvpath/blob/main/LICENSE).
|
|
142
|
+
|
|
143
|
+
## Links
|
|
144
|
+
|
|
145
|
+
- Website: https://lianes8studio.com
|
|
146
|
+
- GitHub: https://github.com/JaviLianes8
|
|
147
|
+
- LinkedIn: https://www.linkedin.com/in/jlianes/
|