Affected Component
Packaging / PyPI install
Skill ID (if applicable)
No response
Bug Description
When a maintainer mixes editable (pip install -e . from a clone) and PyPI wheel (pip install skillware / pip install -U skillware) on the same Python interpreter, pip can leave orphaned or duplicate skillware distribution metadata. The CLI then fails to resolve a version string and prints:
- Interactive splash:
Skillware vNone — Skill Management Framework
skillware --version → skillware None
Pip also breaks against the corrupt registration (pip show may crash; pip uninstall may fail with uninstall-no-record-file).
Expected: Skillware v0.5.4 on splash and skillware 0.5.4 for --version; pip show skillware succeeds.
Observed: Maintainer machine, Windows 11, Python 3.13, after upgrading from an editable 0.5.1-era install to PyPI 0.5.4 without a clean uninstall (Sep 2026).
Not a PyPI wheel defect — published 0.5.4 has valid METADATA and RECORD on a clean install. This is a local install-state footgun for contributors who switch clone dev ↔ global PyPI testing on one Python.
Version display code unchanged between v0.5.1 and v0.5.4 (_package_version_str() in skillware/cli.py, since #222). Security policy / 0.5.4 release chore unrelated. CLI themes (#248 / #305) unrelated.
Impact
| Audience |
Risk |
End users — clean pip install skillware or pip install -U skillware |
Low |
| Maintainers — editable + PyPI on same Python |
High (scenario we hit post-0.5.4) |
| CI / fresh venvs |
None |
Root cause
_package_version_str() → get_installed_version() → importlib.metadata.version("skillware").
get_installed_version() returns None when metadata is missing, empty, "dev", or unparseable.
- Multiple distributions named
skillware can register; a corrupt one (orphan editable dist-info with no METADATA / RECORD) wins → no parseable Version → f-string prints None.
- Fallback does not coerce invalid values to
"dev" when metadata exists but is broken.
Example orphan (skillware-0.5.1.dist-info/direct_url.json only):
{"dir_info": {"editable": true}, "url": "file:///D:/ARPA/OpenSource/Skillware"}
Suggested product fix
1. Harden _package_version_str() — treat None, "", literal "None" as invalid; final fallback "dev". Add test with mocked corrupt metadata.
2. detect_install_conflicts() in version_policy.py — flag duplicate distributions, missing Version / Metadata-Version, editable + wheel on same prefix, orphan dist-info (no RECORD).
3. Surface warnings
- CLI startup: dim stderr one-liner (like
emit_upgrade_advisory) when conflicts detected.
skillware doctor --install: full report + copy-paste fix commands (Windows + Unix). Goal: one command to diagnose.
- Optional: install block in
skillware config show.
4. CONTRIBUTING.md — subsection Editable vs PyPI on the same Python: one mode per interpreter; py -3.13 -m pip on Windows; uninstall before switching; manual cleanup if uninstall-no-record-file.
5. Optional: scripts/dev_install.ps1 / scripts/dev_install.sh — uninstall, remove orphans if needed, pip install -e ".[dev,all]".
Acceptance criteria
Out of scope
- Fixing pip uninstall upstream
- Auto-deleting site-packages without user consent
- Changing end-user PyPI install flow
Steps to Reproduce
- Clone repo; install editable on Python 3.13:
cd D:\path\to\skillware
py -3.13 -m pip install -e ".[dev,all]"
- Without uninstalling, install or upgrade from PyPI on the same interpreter:
py -3.13 -m pip install -U skillware
or py -3.13 -m pip install skillware==0.5.4.
- Optionally repeat across releases so old
skillware-0.5.1.dist-info (editable marker) survives alongside a newer wheel.
- Run:
skillware
skillware --version
py -3.13 -m pip show skillware
py -3.13 -m pip uninstall skillware -y
Actual (corrupt state): vNone; pip show may crash; pip uninstall may fail.
Orphan artifacts (example)
Under %LOCALAPPDATA%\Programs\Python\Python313\Lib\site-packages\:
skillware-0.5.1.dist-info/ — orphan editable; often only direct_url.json, no METADATA, no RECORD
skillware-0.5.4.dist-info/ — valid wheel metadata
skillware/ — leftover package dir from wheel
- Repo
skillware.egg-info/ — second editable marker when working from clone
Manual recovery (workaround today)
If pip uninstall works:
py -3.13 -m pip uninstall skillware -y
py -3.13 -m pip install skillware==0.5.4
If pip uninstall fails (uninstall-no-record-file):
rmdir /s /q "%LOCALAPPDATA%\Programs\Python\Python313\Lib\site-packages\skillware"
rmdir /s /q "%LOCALAPPDATA%\Programs\Python\Python313\Lib\site-packages\skillware-0.5.1.dist-info"
rmdir /s /q "%LOCALAPPDATA%\Programs\Python\Python313\Lib\site-packages\skillware-0.5.4.dist-info"
del "%LOCALAPPDATA%\Programs\Python\Python313\Scripts\skillware.exe"
cd %USERPROFILE%
py -3.13 -m pip install --force-reinstall skillware==0.5.4
Editable dev only (one mode per Python):
cd /d D:\ARPA\OpenSource\Skillware
py -3.13 -m pip uninstall skillware -y
py -3.13 -m pip install -e ".[dev,all]"
Rule: do not keep editable and PyPI wheel on the same interpreter; uninstall before switching.
Error Logs
C:\Users\vpeil>skillware --version
skillware None
C:\Users\vpeil>skillware
Skillware vNone — Skill Management Framework
C:\Users\vpeil>py -3.13 -m pip show skillware
ERROR: Exception:
...
File "...pip\_internal\commands\show.py", line 192, in print_results
metadata_version_tuple = tuple(map(int, dist.metadata_version.split(".")))
ValueError: invalid literal for int() with base 10: ''
C:\Users\vpeil>py -3.13 -m pip uninstall skillware -y
Found existing installation: skillware None
error: uninstall-no-record-file
× Cannot uninstall skillware None
╰─> The package's contents are unknown: no RECORD file was found for skillware.
Environment
Windows 11 (10.0.26200)
Python 3.13 (py launcher: py -3.13)
Install: pip install -e . from clone, then pip install skillware==0.5.4 on same interpreter
PyPI wheel 0.5.4 valid on clean install; corruption from overlapping registrations
Accidentally also installed on Python 3.9 from same repo (separate site-packages — avoid)
Config: ~/.config/skillware/config.yaml and/or .skillware.yaml (unrelated)
Affected Component
Packaging / PyPI install
Skill ID (if applicable)
No response
Bug Description
When a maintainer mixes editable (
pip install -e .from a clone) and PyPI wheel (pip install skillware/pip install -U skillware) on the same Python interpreter, pip can leave orphaned or duplicateskillwaredistribution metadata. The CLI then fails to resolve a version string and prints:Skillware vNone — Skill Management Frameworkskillware --version→skillware NonePip also breaks against the corrupt registration (
pip showmay crash;pip uninstallmay fail withuninstall-no-record-file).Expected:
Skillware v0.5.4on splash andskillware 0.5.4for--version;pip show skillwaresucceeds.Observed: Maintainer machine, Windows 11, Python 3.13, after upgrading from an editable 0.5.1-era install to PyPI
0.5.4without a clean uninstall (Sep 2026).Not a PyPI wheel defect — published
0.5.4has validMETADATAandRECORDon a clean install. This is a local install-state footgun for contributors who switch clone dev ↔ global PyPI testing on one Python.Version display code unchanged between
v0.5.1andv0.5.4(_package_version_str()inskillware/cli.py, since #222). Security policy / 0.5.4 release chore unrelated. CLI themes (#248 / #305) unrelated.Impact
pip install skillwareorpip install -U skillwareRoot cause
_package_version_str()→get_installed_version()→importlib.metadata.version("skillware").get_installed_version()returnsNonewhen metadata is missing, empty,"dev", or unparseable.skillwarecan register; a corrupt one (orphan editable dist-info with noMETADATA/RECORD) wins → no parseableVersion→ f-string printsNone."dev"when metadata exists but is broken.Example orphan (
skillware-0.5.1.dist-info/direct_url.jsononly):{"dir_info": {"editable": true}, "url": "file:///D:/ARPA/OpenSource/Skillware"}Suggested product fix
1. Harden
_package_version_str()— treatNone,"", literal"None"as invalid; final fallback"dev". Add test with mocked corrupt metadata.2.
detect_install_conflicts()inversion_policy.py— flag duplicate distributions, missingVersion/Metadata-Version, editable + wheel on same prefix, orphan dist-info (noRECORD).3. Surface warnings
emit_upgrade_advisory) when conflicts detected.skillware doctor --install: full report + copy-paste fix commands (Windows + Unix). Goal: one command to diagnose.skillware config show.4. CONTRIBUTING.md — subsection Editable vs PyPI on the same Python: one mode per interpreter;
py -3.13 -m pipon Windows; uninstall before switching; manual cleanup ifuninstall-no-record-file.5. Optional:
scripts/dev_install.ps1/scripts/dev_install.sh— uninstall, remove orphans if needed,pip install -e ".[dev,all]".Acceptance criteria
_package_version_str()never returnsNoneor emptydetect_install_conflicts()identifies duplicate / orphan installsskillware doctor --installreports health + fix commands (exit 0 = ok, 1 = conflicts)[Unreleased]entryOut of scope
Steps to Reproduce
py -3.13 -m pip install skillware==0.5.4.skillware-0.5.1.dist-info(editable marker) survives alongside a newer wheel.Actual (corrupt state):
vNone;pip showmay crash;pip uninstallmay fail.Orphan artifacts (example)
Under
%LOCALAPPDATA%\Programs\Python\Python313\Lib\site-packages\:skillware-0.5.1.dist-info/— orphan editable; often onlydirect_url.json, noMETADATA, noRECORDskillware-0.5.4.dist-info/— valid wheel metadataskillware/— leftover package dir from wheelskillware.egg-info/— second editable marker when working from cloneManual recovery (workaround today)
If
pip uninstallworks:py -3.13 -m pip uninstall skillware -y py -3.13 -m pip install skillware==0.5.4If
pip uninstallfails (uninstall-no-record-file):Editable dev only (one mode per Python):
Rule: do not keep editable and PyPI wheel on the same interpreter; uninstall before switching.
Error Logs
Environment