unctools 0.1.0__tar.gz → 0.2.2__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 (51) hide show
  1. unctools-0.2.2/PKG-INFO +226 -0
  2. unctools-0.2.2/README.md +177 -0
  3. unctools-0.2.2/docs/api-stability.md +51 -0
  4. {unctools-0.1.0 → unctools-0.2.2}/examples/basic_usage.py +16 -26
  5. {unctools-0.1.0 → unctools-0.2.2}/pyproject.toml +5 -1
  6. {unctools-0.1.0 → unctools-0.2.2}/tests/basic_functionality_test.py +8 -10
  7. {unctools-0.1.0 → unctools-0.2.2}/tests/test_converter.py +1 -19
  8. {unctools-0.1.0 → unctools-0.2.2}/tests/test_converter_v2.py +2 -7
  9. {unctools-0.1.0 → unctools-0.2.2}/tests/test_detector.py +15 -15
  10. {unctools-0.1.0 → unctools-0.2.2}/tests/test_framework.py +4 -0
  11. unctools-0.2.2/tests/test_import_stability.py +110 -0
  12. unctools-0.2.2/tests/test_operations.py +363 -0
  13. {unctools-0.1.0 → unctools-0.2.2}/tests/test_win32net_warning.py +48 -44
  14. {unctools-0.1.0 → unctools-0.2.2}/tests/test_windows_imports.py +4 -6
  15. unctools-0.2.2/tests/test_wnet_enrichment.py +101 -0
  16. {unctools-0.1.0 → unctools-0.2.2}/unctools/__init__.py +15 -10
  17. unctools-0.2.2/unctools/_version.py +92 -0
  18. {unctools-0.1.0 → unctools-0.2.2}/unctools/converter.py +163 -21
  19. {unctools-0.1.0 → unctools-0.2.2}/unctools/detector.py +153 -4
  20. unctools-0.2.2/unctools/operations.py +42 -0
  21. {unctools-0.1.0 → unctools-0.2.2}/unctools/utils/compat.py +3 -71
  22. unctools-0.2.2/unctools.egg-info/PKG-INFO +226 -0
  23. {unctools-0.1.0 → unctools-0.2.2}/unctools.egg-info/SOURCES.txt +4 -1
  24. unctools-0.1.0/PKG-INFO +0 -189
  25. unctools-0.1.0/README.md +0 -140
  26. unctools-0.1.0/examples/batch_operations.py +0 -302
  27. unctools-0.1.0/tests/test_operations.py +0 -649
  28. unctools-0.1.0/unctools/operations.py +0 -562
  29. unctools-0.1.0/unctools.egg-info/PKG-INFO +0 -189
  30. {unctools-0.1.0 → unctools-0.2.2}/LICENSE +0 -0
  31. {unctools-0.1.0 → unctools-0.2.2}/MANIFEST.in +0 -0
  32. {unctools-0.1.0 → unctools-0.2.2}/docs/implementation-guide.md +0 -0
  33. {unctools-0.1.0 → unctools-0.2.2}/docs/implementation-summary.md +0 -0
  34. {unctools-0.1.0 → unctools-0.2.2}/docs/integration-guide.md +0 -0
  35. {unctools-0.1.0 → unctools-0.2.2}/examples/windows_zone_fix.py +0 -0
  36. {unctools-0.1.0 → unctools-0.2.2}/setup.cfg +0 -0
  37. {unctools-0.1.0 → unctools-0.2.2}/setup.py +0 -0
  38. {unctools-0.1.0 → unctools-0.2.2}/tests/__init__.py +0 -0
  39. {unctools-0.1.0 → unctools-0.2.2}/tests/conftest.py +0 -0
  40. {unctools-0.1.0 → unctools-0.2.2}/tests/test_windows.py +0 -0
  41. {unctools-0.1.0 → unctools-0.2.2}/unctools/utils/__init__.py +0 -0
  42. {unctools-0.1.0 → unctools-0.2.2}/unctools/utils/logger.py +0 -0
  43. {unctools-0.1.0 → unctools-0.2.2}/unctools/utils/validation.py +0 -0
  44. {unctools-0.1.0 → unctools-0.2.2}/unctools/windows/__init__.py +0 -0
  45. {unctools-0.1.0 → unctools-0.2.2}/unctools/windows/network.py +0 -0
  46. {unctools-0.1.0 → unctools-0.2.2}/unctools/windows/registry.py +0 -0
  47. {unctools-0.1.0 → unctools-0.2.2}/unctools/windows/security.py +0 -0
  48. {unctools-0.1.0 → unctools-0.2.2}/unctools.egg-info/dependency_links.txt +0 -0
  49. {unctools-0.1.0 → unctools-0.2.2}/unctools.egg-info/not-zip-safe +0 -0
  50. {unctools-0.1.0 → unctools-0.2.2}/unctools.egg-info/requires.txt +0 -0
  51. {unctools-0.1.0 → unctools-0.2.2}/unctools.egg-info/top_level.txt +0 -0
@@ -0,0 +1,226 @@
1
+ Metadata-Version: 2.4
2
+ Name: unctools
3
+ Version: 0.2.2
4
+ Summary: A comprehensive toolkit for handling UNC paths, network drives, and substituted drives
5
+ Home-page: https://github.com/djdacy/unctools
6
+ Author: Dustin Darcy
7
+ Author-email: Dustin Darcy <your.email@example.com>
8
+ License: MIT
9
+ Project-URL: Homepage, https://github.com/djdarcy/unctools
10
+ Project-URL: Bug Reports, https://github.com/djdarcy/unctools/issues
11
+ Project-URL: Source, https://github.com/djdarcy/unctools
12
+ Project-URL: Documentation, https://github.com/djdarcy/unctools#readme
13
+ Keywords: unc,network,windows,path,file,share,subst
14
+ Classifier: Development Status :: 3 - Alpha
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.6
19
+ Classifier: Programming Language :: Python :: 3.7
20
+ Classifier: Programming Language :: Python :: 3.8
21
+ Classifier: Programming Language :: Python :: 3.9
22
+ Classifier: Programming Language :: Python :: 3.10
23
+ Classifier: Operating System :: Microsoft :: Windows
24
+ Classifier: Operating System :: POSIX :: Linux
25
+ Classifier: Operating System :: MacOS :: MacOS X
26
+ Classifier: Topic :: System :: Filesystems
27
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
28
+ Requires-Python: >=3.6
29
+ Description-Content-Type: text/markdown
30
+ License-File: LICENSE
31
+ Requires-Dist: pathlib; python_version < "3.4"
32
+ Provides-Extra: windows
33
+ Requires-Dist: pywin32>=223; extra == "windows"
34
+ Requires-Dist: pypiwin32>=223; extra == "windows"
35
+ Provides-Extra: dev
36
+ Requires-Dist: pytest>=6.0.0; extra == "dev"
37
+ Requires-Dist: pytest-cov>=2.10.0; extra == "dev"
38
+ Requires-Dist: flake8>=3.8.0; extra == "dev"
39
+ Requires-Dist: black>=20.8b1; extra == "dev"
40
+ Requires-Dist: tox>=3.20.0; extra == "dev"
41
+ Provides-Extra: docs
42
+ Requires-Dist: sphinx>=4.0.0; extra == "docs"
43
+ Requires-Dist: sphinx-rtd-theme>=0.5.0; extra == "docs"
44
+ Requires-Dist: myst-parser>=0.15.0; extra == "docs"
45
+ Dynamic: author
46
+ Dynamic: home-page
47
+ Dynamic: license-file
48
+ Dynamic: requires-python
49
+
50
+ # UNCtools
51
+
52
+ [![PyPI](https://img.shields.io/pypi/v/unctools?color=green)](https://pypi.org/project/unctools/)
53
+ [![Release Date](https://img.shields.io/github/release-date/DazzleLib/UNCtools?color=green)](https://github.com/DazzleLib/UNCtools/releases)
54
+ [![Python 3.6+](https://img.shields.io/badge/python-3.6+-blue.svg)](https://www.python.org/downloads/)
55
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
56
+ [![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20Linux%20%7C%20macOS-lightgrey.svg)](#platform-compatibility)
57
+
58
+ **Windows UNC path handling and network drive utilities: convert between `\\server\share` and mapped drives, classify where paths come from, and probe what's actually reachable.**
59
+
60
+ ## The Problem
61
+
62
+ On Windows, the same file often has two names: the UNC form (`\\server\share\folder\file.txt`) and a mapped-drive form (`Z:\folder\file.txt`). Tools break when handed the one they didn't expect -- network drives disconnect, `subst` drives masquerade as real ones, security zones silently block UNC access, and scripts that worked on one machine fail on another because the drive mappings differ.
63
+
64
+ **UNCtools** answers the identity questions: *is this path UNC / network / subst / local -- and what is its other name?* It converts between path forms using the system's live mappings, classifies path origins, probes accessibility across both name variants, and (on Windows) manages the security zones and drive mappings themselves.
65
+
66
+ > [!NOTE]
67
+ > UNCtools is the **L0 path-identity layer** of the [DazzleLib stack](https://github.com/DazzleLib/.github/blob/main/docs/STACK-MAP.md): it may probe the filesystem read-only to answer identity questions; it never mutates or transfers content (file operations live in [dazzle-filekit](https://github.com/DazzleLib/dazzle-filekit)). The public surface is locked and machine-checked -- see [docs/api-stability.md](docs/api-stability.md).
68
+
69
+ ## Quick Start
70
+
71
+ ```bash
72
+ pip install unctools # or equivalently: dazzle-unctools
73
+ ```
74
+
75
+ ```python
76
+ from unctools import convert_to_local, classify_path_origin
77
+
78
+ local = convert_to_local(r"\\server\share\project") # -> Z:\project (if mapped)
79
+ origin = classify_path_origin(local) # -> "network"
80
+ ```
81
+
82
+ ## Features
83
+
84
+ - **Path conversion**: UNC ↔ mapped-drive translation from the system's live network mappings (win32net with `net use` fallback)
85
+ - **Origin classification**: `classify_path_origin` -- `unc` / `network` / `subst` / `local` / `removable` / `cdrom` / `ramdisk`
86
+ - **Identity probes**: existence and accessibility checks that try *both* name variants of a path
87
+ - **UNC path algebra**: parse and build `\\server\share\rest` components
88
+ - **Issue detection**: MAX_PATH violations, broken mappings, servers missing from the Intranet security zone
89
+ - **Windows management** (optional extra): security zones, share enumeration, drive mapping create/remove
90
+ - **Cross-platform safe**: imports everywhere; Windows-specific features degrade gracefully on Unix
91
+
92
+ ## Installation
93
+
94
+ ```bash
95
+ pip install unctools # standard (or: dazzle-unctools)
96
+ pip install unctools[windows] # + pywin32 for the rich Windows APIs
97
+ ```
98
+
99
+ ```bash
100
+ # Development
101
+ git clone https://github.com/DazzleLib/UNCtools.git
102
+ cd UNCtools
103
+ pip install -e .[dev]
104
+ ```
105
+
106
+ ## Usage
107
+
108
+ ### Basic Path Conversion
109
+
110
+ ```python
111
+ from unctools import convert_to_local, convert_to_unc
112
+
113
+ # Convert UNC path to local drive path
114
+ local_path = convert_to_local("\\\\server\\share\\folder\\file.txt")
115
+ # Result (if mapped): "Z:\\folder\\file.txt"
116
+
117
+ # Convert local drive path back to UNC
118
+ unc_path = convert_to_unc("Z:\\folder\\file.txt")
119
+ # Result: "\\\\server\\share\\folder\\file.txt"
120
+ ```
121
+
122
+ ### Path Detection
123
+
124
+ ```python
125
+ from unctools import is_unc_path, is_network_drive, is_subst_drive, classify_path_origin
126
+
127
+ # Check if a path is a UNC path
128
+ if is_unc_path("\\\\server\\share\\file.txt"):
129
+ print("This is a UNC path")
130
+
131
+ # Check if a drive is a network drive
132
+ if is_network_drive("Z:"):
133
+ print("Z: is a network drive")
134
+
135
+ # Classify WHERE a path comes from
136
+ origin = classify_path_origin("C:\\Users\\")
137
+ # Result: "local", "network", "subst", "unc", etc.
138
+ ```
139
+
140
+ ### Identity Probes & Batch Conversion
141
+
142
+ ```python
143
+ from unctools import file_exists, find_accessible_path, batch_convert
144
+
145
+ # Does the file exist under EITHER of its names (UNC or mapped)?
146
+ if file_exists("\\\\server\\share\\file.txt"):
147
+ print("Reachable under at least one name")
148
+
149
+ # Which name variant actually works right now?
150
+ usable = find_accessible_path("\\\\server\\share\\file.txt")
151
+ # Result: Path("Z:\\file.txt"), Path("\\\\server\\share\\file.txt"), or None
152
+
153
+ # Convert multiple paths at once
154
+ paths = ["\\\\server\\share\\file1.txt", "\\\\server\\share\\file2.txt"]
155
+ converted = batch_convert(paths, to_unc=False)
156
+ ```
157
+
158
+ ### UNC Path Algebra
159
+
160
+ ```python
161
+ from unctools import get_unc_path_elements, build_unc_path
162
+
163
+ server, share, rest = get_unc_path_elements("\\\\server\\share\\folder\\file.txt")
164
+ # Result: ("server", "share", "folder\\file.txt")
165
+
166
+ unc = build_unc_path("server", "share", "folder/file.txt")
167
+ # Result: "\\\\server\\share\\folder/file.txt"
168
+ ```
169
+
170
+ ### Windows Security Zones
171
+
172
+ ```python
173
+ from unctools.windows import fix_security_zone, add_to_intranet_zone
174
+
175
+ # Fix security zone issues for a server
176
+ fix_security_zone("server")
177
+
178
+ # Add a server to the Local Intranet zone
179
+ add_to_intranet_zone("server")
180
+ ```
181
+
182
+ ### Network Drive Management
183
+
184
+ ```python
185
+ from unctools.windows import create_network_mapping, remove_network_mapping
186
+
187
+ # Create a network drive mapping
188
+ success, drive = create_network_mapping("\\\\server\\share", "Z:")
189
+
190
+ # Remove a network drive mapping
191
+ remove_network_mapping("Z:")
192
+ ```
193
+
194
+ ## Platform Compatibility
195
+
196
+ | Platform | Status |
197
+ |----------|--------|
198
+ | Windows | Full functionality: conversion, classification, probes, security zones, drive management |
199
+ | Linux / macOS | Path algebra and syntax checks work; mapping-dependent features degrade gracefully (no-ops / passthrough) |
200
+
201
+ ## Requirements
202
+
203
+ - **Python 3.6+** (3.9-3.13 tested in CI)
204
+ - **pywin32** (optional, via `unctools[windows]`) for the rich Windows APIs -- core features fall back to `net use` parsing without it
205
+
206
+ ## Development
207
+
208
+ ```bash
209
+ python -m pytest tests/ # 50+ tests; includes the api-stability import canary
210
+ black unctools
211
+ flake8 unctools
212
+ ```
213
+
214
+ The public API surface is locked: see **[docs/api-stability.md](docs/api-stability.md)** for the policy, the active deprecation shims (`get_path_type` -> `classify_path_origin`, removed in 0.3.0), and known consumers. Changes follow the [stack's](https://github.com/DazzleLib/.github/blob/main/docs/STACK-MAP.md) noisy-shim deprecation policy -- never silent.
215
+
216
+ ## Contributing
217
+
218
+ Contributions welcome! Please open an issue or submit a pull request.
219
+
220
+ Like the project?
221
+
222
+ [!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/djdarcy)
223
+
224
+ ## License
225
+
226
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,177 @@
1
+ # UNCtools
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/unctools?color=green)](https://pypi.org/project/unctools/)
4
+ [![Release Date](https://img.shields.io/github/release-date/DazzleLib/UNCtools?color=green)](https://github.com/DazzleLib/UNCtools/releases)
5
+ [![Python 3.6+](https://img.shields.io/badge/python-3.6+-blue.svg)](https://www.python.org/downloads/)
6
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
7
+ [![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20Linux%20%7C%20macOS-lightgrey.svg)](#platform-compatibility)
8
+
9
+ **Windows UNC path handling and network drive utilities: convert between `\\server\share` and mapped drives, classify where paths come from, and probe what's actually reachable.**
10
+
11
+ ## The Problem
12
+
13
+ On Windows, the same file often has two names: the UNC form (`\\server\share\folder\file.txt`) and a mapped-drive form (`Z:\folder\file.txt`). Tools break when handed the one they didn't expect -- network drives disconnect, `subst` drives masquerade as real ones, security zones silently block UNC access, and scripts that worked on one machine fail on another because the drive mappings differ.
14
+
15
+ **UNCtools** answers the identity questions: *is this path UNC / network / subst / local -- and what is its other name?* It converts between path forms using the system's live mappings, classifies path origins, probes accessibility across both name variants, and (on Windows) manages the security zones and drive mappings themselves.
16
+
17
+ > [!NOTE]
18
+ > UNCtools is the **L0 path-identity layer** of the [DazzleLib stack](https://github.com/DazzleLib/.github/blob/main/docs/STACK-MAP.md): it may probe the filesystem read-only to answer identity questions; it never mutates or transfers content (file operations live in [dazzle-filekit](https://github.com/DazzleLib/dazzle-filekit)). The public surface is locked and machine-checked -- see [docs/api-stability.md](docs/api-stability.md).
19
+
20
+ ## Quick Start
21
+
22
+ ```bash
23
+ pip install unctools # or equivalently: dazzle-unctools
24
+ ```
25
+
26
+ ```python
27
+ from unctools import convert_to_local, classify_path_origin
28
+
29
+ local = convert_to_local(r"\\server\share\project") # -> Z:\project (if mapped)
30
+ origin = classify_path_origin(local) # -> "network"
31
+ ```
32
+
33
+ ## Features
34
+
35
+ - **Path conversion**: UNC ↔ mapped-drive translation from the system's live network mappings (win32net with `net use` fallback)
36
+ - **Origin classification**: `classify_path_origin` -- `unc` / `network` / `subst` / `local` / `removable` / `cdrom` / `ramdisk`
37
+ - **Identity probes**: existence and accessibility checks that try *both* name variants of a path
38
+ - **UNC path algebra**: parse and build `\\server\share\rest` components
39
+ - **Issue detection**: MAX_PATH violations, broken mappings, servers missing from the Intranet security zone
40
+ - **Windows management** (optional extra): security zones, share enumeration, drive mapping create/remove
41
+ - **Cross-platform safe**: imports everywhere; Windows-specific features degrade gracefully on Unix
42
+
43
+ ## Installation
44
+
45
+ ```bash
46
+ pip install unctools # standard (or: dazzle-unctools)
47
+ pip install unctools[windows] # + pywin32 for the rich Windows APIs
48
+ ```
49
+
50
+ ```bash
51
+ # Development
52
+ git clone https://github.com/DazzleLib/UNCtools.git
53
+ cd UNCtools
54
+ pip install -e .[dev]
55
+ ```
56
+
57
+ ## Usage
58
+
59
+ ### Basic Path Conversion
60
+
61
+ ```python
62
+ from unctools import convert_to_local, convert_to_unc
63
+
64
+ # Convert UNC path to local drive path
65
+ local_path = convert_to_local("\\\\server\\share\\folder\\file.txt")
66
+ # Result (if mapped): "Z:\\folder\\file.txt"
67
+
68
+ # Convert local drive path back to UNC
69
+ unc_path = convert_to_unc("Z:\\folder\\file.txt")
70
+ # Result: "\\\\server\\share\\folder\\file.txt"
71
+ ```
72
+
73
+ ### Path Detection
74
+
75
+ ```python
76
+ from unctools import is_unc_path, is_network_drive, is_subst_drive, classify_path_origin
77
+
78
+ # Check if a path is a UNC path
79
+ if is_unc_path("\\\\server\\share\\file.txt"):
80
+ print("This is a UNC path")
81
+
82
+ # Check if a drive is a network drive
83
+ if is_network_drive("Z:"):
84
+ print("Z: is a network drive")
85
+
86
+ # Classify WHERE a path comes from
87
+ origin = classify_path_origin("C:\\Users\\")
88
+ # Result: "local", "network", "subst", "unc", etc.
89
+ ```
90
+
91
+ ### Identity Probes & Batch Conversion
92
+
93
+ ```python
94
+ from unctools import file_exists, find_accessible_path, batch_convert
95
+
96
+ # Does the file exist under EITHER of its names (UNC or mapped)?
97
+ if file_exists("\\\\server\\share\\file.txt"):
98
+ print("Reachable under at least one name")
99
+
100
+ # Which name variant actually works right now?
101
+ usable = find_accessible_path("\\\\server\\share\\file.txt")
102
+ # Result: Path("Z:\\file.txt"), Path("\\\\server\\share\\file.txt"), or None
103
+
104
+ # Convert multiple paths at once
105
+ paths = ["\\\\server\\share\\file1.txt", "\\\\server\\share\\file2.txt"]
106
+ converted = batch_convert(paths, to_unc=False)
107
+ ```
108
+
109
+ ### UNC Path Algebra
110
+
111
+ ```python
112
+ from unctools import get_unc_path_elements, build_unc_path
113
+
114
+ server, share, rest = get_unc_path_elements("\\\\server\\share\\folder\\file.txt")
115
+ # Result: ("server", "share", "folder\\file.txt")
116
+
117
+ unc = build_unc_path("server", "share", "folder/file.txt")
118
+ # Result: "\\\\server\\share\\folder/file.txt"
119
+ ```
120
+
121
+ ### Windows Security Zones
122
+
123
+ ```python
124
+ from unctools.windows import fix_security_zone, add_to_intranet_zone
125
+
126
+ # Fix security zone issues for a server
127
+ fix_security_zone("server")
128
+
129
+ # Add a server to the Local Intranet zone
130
+ add_to_intranet_zone("server")
131
+ ```
132
+
133
+ ### Network Drive Management
134
+
135
+ ```python
136
+ from unctools.windows import create_network_mapping, remove_network_mapping
137
+
138
+ # Create a network drive mapping
139
+ success, drive = create_network_mapping("\\\\server\\share", "Z:")
140
+
141
+ # Remove a network drive mapping
142
+ remove_network_mapping("Z:")
143
+ ```
144
+
145
+ ## Platform Compatibility
146
+
147
+ | Platform | Status |
148
+ |----------|--------|
149
+ | Windows | Full functionality: conversion, classification, probes, security zones, drive management |
150
+ | Linux / macOS | Path algebra and syntax checks work; mapping-dependent features degrade gracefully (no-ops / passthrough) |
151
+
152
+ ## Requirements
153
+
154
+ - **Python 3.6+** (3.9-3.13 tested in CI)
155
+ - **pywin32** (optional, via `unctools[windows]`) for the rich Windows APIs -- core features fall back to `net use` parsing without it
156
+
157
+ ## Development
158
+
159
+ ```bash
160
+ python -m pytest tests/ # 50+ tests; includes the api-stability import canary
161
+ black unctools
162
+ flake8 unctools
163
+ ```
164
+
165
+ The public API surface is locked: see **[docs/api-stability.md](docs/api-stability.md)** for the policy, the active deprecation shims (`get_path_type` -> `classify_path_origin`, removed in 0.3.0), and known consumers. Changes follow the [stack's](https://github.com/DazzleLib/.github/blob/main/docs/STACK-MAP.md) noisy-shim deprecation policy -- never silent.
166
+
167
+ ## Contributing
168
+
169
+ Contributions welcome! Please open an issue or submit a pull request.
170
+
171
+ Like the project?
172
+
173
+ [!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/djdarcy)
174
+
175
+ ## License
176
+
177
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,51 @@
1
+ # API Stability
2
+
3
+ UNCtools is the L0 path-identity layer of the
4
+ [DazzleLib stack](https://github.com/DazzleLib/.github/blob/main/docs/STACK-MAP.md).
5
+ Its public surface is locked and machine-checked by
6
+ `tests/test_import_stability.py` -- if that canary fails, a consumer somewhere
7
+ breaks: follow the policy below, never silently fix the test.
8
+
9
+ ## Policy
10
+
11
+ 1. **Locked symbols never vanish silently.** Removal/rename ships a NOISY
12
+ `DeprecationWarning` shim naming the new home and removal version,
13
+ registered in the stack's alias register, removed on schedule.
14
+ 2. **The layer charter is not negotiable** (STACK-MAP rule 3a): this library
15
+ may probe the filesystem read-only to answer identity questions; it never
16
+ mutates or transfers content. Functions that do are rejected, not deprecated.
17
+ 3. **Name hygiene** (STACK-MAP rule 7): before exporting a public symbol,
18
+ grep the stack -- same-name-different-semantics requires a layer-teaching
19
+ rename (that is how `classify_path_origin` got its name).
20
+
21
+ ## Locked surface (0.2.0)
22
+
23
+ | Module | Symbols |
24
+ |---|---|
25
+ | `unctools` (top level) | `convert_to_local`, `convert_to_unc`, `batch_convert`, `get_unc_path_elements`, `build_unc_path`, `is_unc_path`, `is_network_drive`, `is_subst_drive`, `classify_path_origin`, `get_network_mappings`, `detect_path_issues`, `file_exists`, `is_path_accessible`, `find_accessible_path`, `configure_logging`, `get_version` |
26
+ | `unctools.converter` | `UNCConverter`, `convert_to_local`, `convert_to_unc`, `batch_convert`, `get_unc_path_elements`, `build_unc_path`, `refresh_mappings`, `get_mappings`, `parse_unc_path`, `join_unc_path` |
27
+ | `unctools.detector` | the origin classifiers + probes listed above, plus `get_drive_type`, `get_subst_target`, `get_network_target`, `is_server_in_intranet_zone` |
28
+ | `unctools.windows.*` | Windows-only security/network/registry surface (unchanged in 0.2.0) |
29
+
30
+ ## Active deprecations
31
+
32
+ | Symbol | Replacement | Warns since | Removed in |
33
+ |---|---|---|---|
34
+ | `get_path_type` | `classify_path_origin` | 0.2.0 | 0.3.0 |
35
+ | `unctools.operations` (module facade) | top-level imports / `converter` / `detector` | 0.2.0 | 0.3.0 |
36
+
37
+ ## Known consumers
38
+
39
+ | Consumer | Symbols | Notes |
40
+ |---|---|---|
41
+ | dazzlecmd (`safedel/_volumes.py`, `fixpath.py`) | `get_drive_type`, `is_network_drive`, `is_unc_path`, `convert_to_local` | optional imports today; harden in stack P4 |
42
+ | dazzlesum | top-level conversion/probe block | soft-imports today; harden in stack P4 |
43
+ | modified_datetime_fix | mixed (incl. a vendored copy to retire) | stack P4 |
44
+ | dazzle-filekit | `[unctools]` extra pin (no runtime import) | becomes a real edge only if/when filekit consumes identity at runtime |
45
+
46
+ ## Consolidation candidates (0.3.0)
47
+
48
+ - `parse_unc_path`/`join_unc_path` vs `get_unc_path_elements`/`build_unc_path`
49
+ (near-duplicates; the latter preserve forward slashes in the relative part)
50
+ - dazzle-lib adoption: derive errors from `dazzle_lib.PathIdentityError`
51
+ (deliberately deferred from 0.2.0 to keep the surgery diff reviewable)
@@ -17,9 +17,9 @@ logging.basicConfig(level=logging.INFO,
17
17
  # Import UNCtools
18
18
  import unctools
19
19
  from unctools import (
20
- convert_to_local, convert_to_unc, normalize_path,
21
- is_unc_path, is_network_drive, is_subst_drive, get_path_type,
22
- safe_open, safe_copy, batch_convert, process_files
20
+ convert_to_local, convert_to_unc,
21
+ is_unc_path, is_network_drive, is_subst_drive, classify_path_origin,
22
+ file_exists, find_accessible_path, batch_convert
23
23
  )
24
24
 
25
25
  def print_section(title):
@@ -43,7 +43,8 @@ def demonstrate_path_conversion():
43
43
  # Show network mappings if on Windows
44
44
  if os.name == 'nt':
45
45
  print("\nNetwork Mappings:")
46
- mappings = unctools.get_mappings()
46
+ from unctools.converter import get_mappings
47
+ mappings = get_mappings()
47
48
  for unc, drive in mappings.items():
48
49
  print(f" {unc} -> {drive}")
49
50
 
@@ -52,10 +53,11 @@ def demonstrate_path_conversion():
52
53
  print(f" UNC -> Local: {unc_path} -> {convert_to_local(unc_path)}")
53
54
  print(f" Local -> UNC: {local_path} -> {convert_to_unc(local_path)}")
54
55
 
55
- # Normalize paths
56
- print("\nPath Normalization:")
57
- print(f" Normalize (prefer local): {normalize_path(unc_path, prefer_unc=False)}")
58
- print(f" Normalize (prefer UNC): {normalize_path(local_path, prefer_unc=True)}")
56
+ # Round-trip explicitly (normalize_path was removed in 0.2.0 -- the
57
+ # explicit converts ARE the API)
58
+ print("\nExplicit round-trip:")
59
+ print(f" To local: {convert_to_local(unc_path)}")
60
+ print(f" To UNC: {convert_to_unc(local_path)}")
59
61
 
60
62
  def demonstrate_path_detection():
61
63
  """Demonstrate path detection functionality."""
@@ -72,7 +74,7 @@ def demonstrate_path_detection():
72
74
 
73
75
  print("Path Type Detection:")
74
76
  for path in paths:
75
- path_type = get_path_type(path)
77
+ path_type = classify_path_origin(path)
76
78
  is_unc = is_unc_path(path)
77
79
  print(f" {path}:")
78
80
  print(f" Type: {path_type}")
@@ -112,14 +114,11 @@ def demonstrate_file_operations():
112
114
  with open(temp_file, "w") as f:
113
115
  f.write("Hello, UNCtools!")
114
116
 
115
- # Safe open
116
- print("\nSafe Open:")
117
- try:
118
- with safe_open(temp_file, "r") as f:
119
- content = f.read()
120
- print(f" Content: {content}")
121
- except Exception as e:
122
- print(f" Error: {e}")
117
+ # Identity probes (safe_open was removed in 0.2.0 -- I/O lives in
118
+ # dazzle-filekit; unctools answers identity questions)
119
+ print("\nIdentity probes:")
120
+ print(f" file_exists: {file_exists(temp_file)}")
121
+ print(f" accessible variant: {find_accessible_path(temp_file)}")
123
122
 
124
123
  # Batch operations
125
124
  print("\nBatch Operations:")
@@ -129,15 +128,6 @@ def demonstrate_file_operations():
129
128
  with open(os.path.join(temp_dir, f"temp_file_{i}.txt"), "w") as f:
130
129
  f.write(f"Test file {i}")
131
130
 
132
- # Process files
133
- print(" Processing files:")
134
- def process_callback(path):
135
- return path.stat().st_size
136
-
137
- results = process_files(temp_dir, process_callback, pattern="temp_file*.txt")
138
- for path, size in results.items():
139
- print(f" {path}: {size} bytes")
140
-
141
131
  # Batch convert
142
132
  print("\n Batch conversion:")
143
133
  paths = [os.path.join(temp_dir, f"temp_file_{i}.txt") for i in range(3)]
@@ -63,7 +63,11 @@ include = ["unctools*"]
63
63
  exclude = ["tests*"]
64
64
 
65
65
  [tool.setuptools.dynamic]
66
- version = {attr = "unctools.__version__"}
66
+ version = {attr = "unctools._version.PIP_VERSION"}
67
+
68
+ [tool.repokit-common]
69
+ version-source = "unctools/_version.py"
70
+ repo-url = "https://github.com/DazzleLib/UNCtools"
67
71
 
68
72
  [tool.setuptools.package-data]
69
73
  unctools = ["py.typed"]
@@ -62,9 +62,9 @@ def run_tests():
62
62
  print("\nTesting core module imports...")
63
63
  try:
64
64
  from unctools import (
65
- convert_to_local, convert_to_unc, normalize_path,
65
+ convert_to_local, convert_to_unc, classify_path_origin,
66
66
  is_unc_path, is_network_drive, is_subst_drive,
67
- safe_open, batch_convert
67
+ file_exists, batch_convert
68
68
  )
69
69
  check(True, "Import core functions")
70
70
  except ImportError as e:
@@ -111,12 +111,12 @@ def run_tests():
111
111
  test_unc_path = r"\\server\share\folder"
112
112
  check(is_unc_path(test_unc_path), f"is_unc_path({test_unc_path}) should be True")
113
113
 
114
- # Test path normalization
114
+ # Test origin classification (normalize_path removed in 0.2.0, D4)
115
115
  try:
116
- normalized = normalize_path(test_path)
117
- check(True, f"normalize_path({test_path}) => {normalized}")
116
+ origin = classify_path_origin(test_path)
117
+ check(True, f"classify_path_origin({test_path}) => {origin}")
118
118
  except Exception as e:
119
- check(False, f"normalize_path({test_path}): {e}")
119
+ check(False, f"classify_path_origin({test_path}): {e}")
120
120
 
121
121
  # Test path conversion (just ensure it doesn't error)
122
122
  try:
@@ -157,10 +157,8 @@ def run_tests():
157
157
  temp_filename = f.name
158
158
  f.write("UNCtools test file")
159
159
 
160
- # Test safe_open
161
- with safe_open(temp_filename, 'r') as f:
162
- content = f.read()
163
- check(content == "UNCtools test file", f"safe_open() and read content: '{content}'")
160
+ # Test file_exists probe (safe_open removed in 0.2.0, D7)
161
+ check(file_exists(temp_filename), f"file_exists({temp_filename}) should be True")
164
162
 
165
163
  # Clean up
166
164
  os.unlink(temp_filename)
@@ -10,7 +10,7 @@ from pathlib import Path
10
10
  from unittest import mock
11
11
 
12
12
  from unctools.converter import (
13
- UNCConverter, convert_to_local, convert_to_unc, normalize_path,
13
+ UNCConverter, convert_to_local, convert_to_unc,
14
14
  parse_unc_path, join_unc_path
15
15
  )
16
16
 
@@ -180,24 +180,6 @@ class TestModuleFunctions:
180
180
  assert result == Path(TEST_UNC_PATH)
181
181
  mock_converter.convert_to_unc.assert_called_once_with(TEST_LOCAL_PATH)
182
182
 
183
- def test_normalize_path(self):
184
- """Test normalize_path function."""
185
- # Test with prefer_unc=False (default)
186
- with mock.patch('unctools.converter.convert_to_local') as mock_convert_local:
187
- mock_convert_local.return_value = Path(TEST_LOCAL_PATH)
188
-
189
- result = normalize_path(TEST_UNC_PATH)
190
- assert result == Path(TEST_LOCAL_PATH)
191
- mock_convert_local.assert_called_once_with(Path(TEST_UNC_PATH))
192
-
193
- # Test with prefer_unc=True
194
- with mock.patch('unctools.converter.convert_to_unc') as mock_convert_unc:
195
- mock_convert_unc.return_value = Path(TEST_UNC_PATH)
196
-
197
- result = normalize_path(TEST_LOCAL_PATH, prefer_unc=True)
198
- assert result == Path(TEST_UNC_PATH)
199
- mock_convert_unc.assert_called_once_with(Path(TEST_LOCAL_PATH))
200
-
201
183
  def test_parse_unc_path(self):
202
184
  """Test parse_unc_path function."""
203
185
  # Test with a valid UNC path
@@ -23,7 +23,7 @@ from tests.test_framework import (
23
23
  # Import UNCtools
24
24
  import unctools
25
25
  from unctools.converter import (
26
- UNCConverter, convert_to_local, convert_to_unc, normalize_path,
26
+ UNCConverter, convert_to_local, convert_to_unc,
27
27
  parse_unc_path, join_unc_path
28
28
  )
29
29
 
@@ -155,12 +155,7 @@ def test_module_functions():
155
155
  path = convert_to_unc(TEST_LOCAL_PATH)
156
156
  assert_is_not_none(path)
157
157
 
158
- # Test normalize_path
159
- path = normalize_path(TEST_UNC_PATH)
160
- assert_is_not_none(path)
161
-
162
- path = normalize_path(TEST_LOCAL_PATH, prefer_unc=True)
163
- assert_is_not_none(path)
158
+ # normalize_path was removed in 0.2.0 (D4) -- the explicit converts ARE the API
164
159
 
165
160
  def test_parse_unc_path():
166
161
  """Test parse_unc_path function."""