mustel 0.1.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.
- mustel-0.1.0/LICENSE +31 -0
- mustel-0.1.0/PKG-INFO +95 -0
- mustel-0.1.0/README.md +69 -0
- mustel-0.1.0/mustel/__init__.py +0 -0
- mustel-0.1.0/mustel/__main__.py +5 -0
- mustel-0.1.0/mustel/main.py +327 -0
- mustel-0.1.0/mustel.egg-info/PKG-INFO +95 -0
- mustel-0.1.0/mustel.egg-info/SOURCES.txt +11 -0
- mustel-0.1.0/mustel.egg-info/dependency_links.txt +1 -0
- mustel-0.1.0/mustel.egg-info/entry_points.txt +2 -0
- mustel-0.1.0/mustel.egg-info/top_level.txt +1 -0
- mustel-0.1.0/pyproject.toml +34 -0
- mustel-0.1.0/setup.cfg +4 -0
mustel-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
Proprietary License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Ameya Kulkarni, Raunak Nayak
|
|
4
|
+
All Rights Reserved.
|
|
5
|
+
|
|
6
|
+
This software and associated documentation files (the "Software") are the
|
|
7
|
+
proprietary property of the copyright holders. The Software is protected by
|
|
8
|
+
copyright laws and international copyright treaties.
|
|
9
|
+
|
|
10
|
+
TERMS AND CONDITIONS:
|
|
11
|
+
|
|
12
|
+
1. LICENSE GRANT: You are granted a limited, non-exclusive, non-transferable
|
|
13
|
+
license to install and use the Software for your personal or internal
|
|
14
|
+
business purposes only.
|
|
15
|
+
|
|
16
|
+
2. RESTRICTIONS: You may NOT:
|
|
17
|
+
- Copy, modify, or create derivative works of the Software
|
|
18
|
+
- Distribute, sublicense, sell, or transfer the Software to any third party
|
|
19
|
+
- Reverse engineer, decompile, or disassemble the Software
|
|
20
|
+
- Remove or alter any proprietary notices on the Software
|
|
21
|
+
|
|
22
|
+
3. NO WARRANTY: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
23
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
24
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
25
|
+
|
|
26
|
+
4. LIMITATION OF LIABILITY: IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
27
|
+
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
28
|
+
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
29
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
30
|
+
|
|
31
|
+
For licensing inquiries, contact: acclaptop47@gmail.com
|
mustel-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mustel
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Simple Python environment inspector - see what's installed across all your Python versions
|
|
5
|
+
Author: Raunak Nayak
|
|
6
|
+
Author-email: Ameya Kulkarni <acclaptop47@gmail.com>
|
|
7
|
+
License: Proprietary
|
|
8
|
+
Keywords: python,environment,packages,pip,inspector
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: Other/Proprietary License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Requires-Python: >=3.8
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
# mustel 🦦
|
|
28
|
+
|
|
29
|
+
A simple Python environment inspector. See what's installed across all your Python versions.
|
|
30
|
+
|
|
31
|
+
## Why?
|
|
32
|
+
|
|
33
|
+
Ever had this happen?
|
|
34
|
+
```
|
|
35
|
+
pip install numpy
|
|
36
|
+
import numpy # ❌ ModuleNotFoundError
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
That's because you have multiple Python versions, and `pip` installed it in a different one!
|
|
40
|
+
|
|
41
|
+
**mustel** helps you see exactly what's installed where.
|
|
42
|
+
|
|
43
|
+
## Install
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install mustel
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Usage
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
mustel # Show packages in current Python
|
|
53
|
+
mustel all # Show all Python installations
|
|
54
|
+
mustel diff # Compare packages across Pythons
|
|
55
|
+
mustel check X # Check if package X exists
|
|
56
|
+
mustel updates # Show outdated packages
|
|
57
|
+
mustel help # Show help
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Examples
|
|
61
|
+
|
|
62
|
+
### See all your Pythons
|
|
63
|
+
```
|
|
64
|
+
> mustel all
|
|
65
|
+
|
|
66
|
+
🦦 mustel — all pythons
|
|
67
|
+
|
|
68
|
+
Found 3 Python(s):
|
|
69
|
+
|
|
70
|
+
------------------------------------------------------------
|
|
71
|
+
★ Python 3.13.7 (current)
|
|
72
|
+
Path: C:\Users\...\Python313\python.exe
|
|
73
|
+
Packages: 151
|
|
74
|
+
|
|
75
|
+
Python 3.14.0
|
|
76
|
+
Path: C:\Users\...\Python314\python.exe
|
|
77
|
+
Packages: 8
|
|
78
|
+
------------------------------------------------------------
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Use with a specific Python
|
|
82
|
+
```bash
|
|
83
|
+
C:\Python314\python.exe -m mustel
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Why "mustel"?
|
|
87
|
+
|
|
88
|
+
Named after the **Mustelidae** family (otters, weasels, ferrets) - small but effective hunters that find things in hidden places! 🦦
|
|
89
|
+
|
|
90
|
+
## License
|
|
91
|
+
|
|
92
|
+
Proprietary - All Rights Reserved.
|
|
93
|
+
Copyright © 2025 Ameya Kulkarni, Raunak Nayak
|
|
94
|
+
|
|
95
|
+
See [LICENSE](LICENSE) for details.
|
mustel-0.1.0/README.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# mustel 🦦
|
|
2
|
+
|
|
3
|
+
A simple Python environment inspector. See what's installed across all your Python versions.
|
|
4
|
+
|
|
5
|
+
## Why?
|
|
6
|
+
|
|
7
|
+
Ever had this happen?
|
|
8
|
+
```
|
|
9
|
+
pip install numpy
|
|
10
|
+
import numpy # ❌ ModuleNotFoundError
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
That's because you have multiple Python versions, and `pip` installed it in a different one!
|
|
14
|
+
|
|
15
|
+
**mustel** helps you see exactly what's installed where.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install mustel
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
mustel # Show packages in current Python
|
|
27
|
+
mustel all # Show all Python installations
|
|
28
|
+
mustel diff # Compare packages across Pythons
|
|
29
|
+
mustel check X # Check if package X exists
|
|
30
|
+
mustel updates # Show outdated packages
|
|
31
|
+
mustel help # Show help
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Examples
|
|
35
|
+
|
|
36
|
+
### See all your Pythons
|
|
37
|
+
```
|
|
38
|
+
> mustel all
|
|
39
|
+
|
|
40
|
+
🦦 mustel — all pythons
|
|
41
|
+
|
|
42
|
+
Found 3 Python(s):
|
|
43
|
+
|
|
44
|
+
------------------------------------------------------------
|
|
45
|
+
★ Python 3.13.7 (current)
|
|
46
|
+
Path: C:\Users\...\Python313\python.exe
|
|
47
|
+
Packages: 151
|
|
48
|
+
|
|
49
|
+
Python 3.14.0
|
|
50
|
+
Path: C:\Users\...\Python314\python.exe
|
|
51
|
+
Packages: 8
|
|
52
|
+
------------------------------------------------------------
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Use with a specific Python
|
|
56
|
+
```bash
|
|
57
|
+
C:\Python314\python.exe -m mustel
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Why "mustel"?
|
|
61
|
+
|
|
62
|
+
Named after the **Mustelidae** family (otters, weasels, ferrets) - small but effective hunters that find things in hidden places! 🦦
|
|
63
|
+
|
|
64
|
+
## License
|
|
65
|
+
|
|
66
|
+
Proprietary - All Rights Reserved.
|
|
67
|
+
Copyright © 2025 Ameya Kulkarni, Raunak Nayak
|
|
68
|
+
|
|
69
|
+
See [LICENSE](LICENSE) for details.
|
|
File without changes
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
# mustel/main.py
|
|
2
|
+
"""
|
|
3
|
+
mustel - Simple Python environment inspector
|
|
4
|
+
A tool to see what's installed across all your Python versions.
|
|
5
|
+
|
|
6
|
+
Named after the Mustelidae family (otters, weasels) - small but effective hunters!
|
|
7
|
+
"""
|
|
8
|
+
import sys
|
|
9
|
+
import os
|
|
10
|
+
import subprocess
|
|
11
|
+
import json
|
|
12
|
+
import platform
|
|
13
|
+
import importlib.util
|
|
14
|
+
|
|
15
|
+
# Fix Windows console encoding for emojis
|
|
16
|
+
if platform.system() == "Windows":
|
|
17
|
+
try:
|
|
18
|
+
sys.stdout.reconfigure(encoding='utf-8')
|
|
19
|
+
except:
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# ============================================================
|
|
24
|
+
# HELPER FUNCTIONS
|
|
25
|
+
# ============================================================
|
|
26
|
+
|
|
27
|
+
def run_cmd(cmd):
|
|
28
|
+
"""Run a command and return output, or None if it fails."""
|
|
29
|
+
try:
|
|
30
|
+
return subprocess.check_output(cmd, stderr=subprocess.DEVNULL, text=True)
|
|
31
|
+
except:
|
|
32
|
+
return None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def get_packages(python_path):
|
|
36
|
+
"""Get dict of {package_name: version} for a Python installation."""
|
|
37
|
+
out = run_cmd([python_path, "-m", "pip", "list", "--format=json"])
|
|
38
|
+
if not out:
|
|
39
|
+
return {}
|
|
40
|
+
try:
|
|
41
|
+
data = json.loads(out)
|
|
42
|
+
return {pkg["name"].lower(): pkg["version"] for pkg in data}
|
|
43
|
+
except:
|
|
44
|
+
return {}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def get_outdated(python_path):
|
|
48
|
+
"""Get dict of {package_name: (current, latest)} for outdated packages."""
|
|
49
|
+
out = run_cmd([python_path, "-m", "pip", "list", "--outdated", "--format=json"])
|
|
50
|
+
if not out:
|
|
51
|
+
return {}
|
|
52
|
+
try:
|
|
53
|
+
data = json.loads(out)
|
|
54
|
+
return {pkg["name"].lower(): (pkg["version"], pkg["latest_version"]) for pkg in data}
|
|
55
|
+
except:
|
|
56
|
+
return {}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def find_all_pythons():
|
|
60
|
+
"""Find all Python installations on the system."""
|
|
61
|
+
found = set()
|
|
62
|
+
current = sys.executable
|
|
63
|
+
|
|
64
|
+
if platform.system() == "Windows":
|
|
65
|
+
# Check common Windows install location
|
|
66
|
+
local_programs = os.path.expandvars(r"%LOCALAPPDATA%\Programs\Python")
|
|
67
|
+
if os.path.exists(local_programs):
|
|
68
|
+
for folder in os.listdir(local_programs):
|
|
69
|
+
exe = os.path.join(local_programs, folder, "python.exe")
|
|
70
|
+
if os.path.exists(exe):
|
|
71
|
+
found.add(exe)
|
|
72
|
+
|
|
73
|
+
# Check where python finds
|
|
74
|
+
out = run_cmd(["where", "python"])
|
|
75
|
+
if out:
|
|
76
|
+
for line in out.splitlines():
|
|
77
|
+
line = line.strip()
|
|
78
|
+
if line.lower().endswith(".exe"):
|
|
79
|
+
found.add(line)
|
|
80
|
+
else:
|
|
81
|
+
# Unix: check python3.x versions
|
|
82
|
+
for minor in range(7, 15):
|
|
83
|
+
out = run_cmd(["which", f"python3.{minor}"])
|
|
84
|
+
if out:
|
|
85
|
+
found.add(out.strip())
|
|
86
|
+
|
|
87
|
+
# Remove current python and normalize paths
|
|
88
|
+
result = []
|
|
89
|
+
current_real = os.path.normcase(os.path.realpath(current))
|
|
90
|
+
seen = set()
|
|
91
|
+
|
|
92
|
+
for path in found:
|
|
93
|
+
try:
|
|
94
|
+
path_real = os.path.normcase(os.path.realpath(path))
|
|
95
|
+
if path_real == current_real:
|
|
96
|
+
continue
|
|
97
|
+
if path_real not in seen:
|
|
98
|
+
seen.add(path_real)
|
|
99
|
+
result.append(path)
|
|
100
|
+
except:
|
|
101
|
+
pass
|
|
102
|
+
|
|
103
|
+
return result
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def is_importable(name):
|
|
107
|
+
"""Check if a module can be imported."""
|
|
108
|
+
return importlib.util.find_spec(name) is not None
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
# ============================================================
|
|
112
|
+
# COMMANDS
|
|
113
|
+
# ============================================================
|
|
114
|
+
|
|
115
|
+
def cmd_list():
|
|
116
|
+
"""Show packages in current Python."""
|
|
117
|
+
exe = sys.executable
|
|
118
|
+
version = sys.version.split()[0]
|
|
119
|
+
|
|
120
|
+
print(f"\n🦦 mustel — Python {version}\n")
|
|
121
|
+
print(f"Path: {exe}\n")
|
|
122
|
+
|
|
123
|
+
packages = get_packages(exe)
|
|
124
|
+
if packages:
|
|
125
|
+
print(f"📦 {len(packages)} packages installed:\n")
|
|
126
|
+
for name in sorted(packages):
|
|
127
|
+
print(f" {name} == {packages[name]}")
|
|
128
|
+
else:
|
|
129
|
+
print(" (no packages found)")
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def cmd_all():
|
|
133
|
+
"""Show all Python installations."""
|
|
134
|
+
print("\n🦦 mustel — all pythons\n")
|
|
135
|
+
|
|
136
|
+
current = sys.executable
|
|
137
|
+
others = find_all_pythons()
|
|
138
|
+
all_pythons = [current] + others
|
|
139
|
+
|
|
140
|
+
print(f"Found {len(all_pythons)} Python(s):\n")
|
|
141
|
+
print("-" * 60)
|
|
142
|
+
|
|
143
|
+
for exe in all_pythons:
|
|
144
|
+
# Get version
|
|
145
|
+
out = run_cmd([exe, "--version"])
|
|
146
|
+
version = out.strip() if out else "unknown"
|
|
147
|
+
|
|
148
|
+
# Get package count
|
|
149
|
+
packages = get_packages(exe)
|
|
150
|
+
count = len(packages)
|
|
151
|
+
|
|
152
|
+
# Mark current
|
|
153
|
+
marker = "★" if exe == current else " "
|
|
154
|
+
label = "(current)" if exe == current else ""
|
|
155
|
+
|
|
156
|
+
print(f"{marker} {version} {label}")
|
|
157
|
+
print(f" Path: {exe}")
|
|
158
|
+
print(f" Packages: {count}\n")
|
|
159
|
+
|
|
160
|
+
print("-" * 60)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def cmd_diff():
|
|
164
|
+
"""Show packages in other Pythons that aren't in current."""
|
|
165
|
+
print("\n🦦 mustel — diff\n")
|
|
166
|
+
|
|
167
|
+
current = sys.executable
|
|
168
|
+
current_packages = get_packages(current)
|
|
169
|
+
others = find_all_pythons()
|
|
170
|
+
|
|
171
|
+
if not others:
|
|
172
|
+
print("No other Python installations found.")
|
|
173
|
+
return
|
|
174
|
+
|
|
175
|
+
print(f"Current Python: {current}")
|
|
176
|
+
print(f"Packages: {len(current_packages)}\n")
|
|
177
|
+
|
|
178
|
+
for other in others:
|
|
179
|
+
other_packages = get_packages(other)
|
|
180
|
+
if not other_packages:
|
|
181
|
+
continue
|
|
182
|
+
|
|
183
|
+
# Find packages in other that aren't in current
|
|
184
|
+
missing = {k: v for k, v in other_packages.items() if k not in current_packages}
|
|
185
|
+
|
|
186
|
+
out = run_cmd([other, "--version"])
|
|
187
|
+
version = out.strip() if out else other
|
|
188
|
+
|
|
189
|
+
print(f"\n{version}")
|
|
190
|
+
print(f" Path: {other}")
|
|
191
|
+
|
|
192
|
+
if missing:
|
|
193
|
+
print(f" 📦 {len(missing)} unique packages:")
|
|
194
|
+
for name in sorted(missing):
|
|
195
|
+
print(f" {name} == {missing[name]}")
|
|
196
|
+
else:
|
|
197
|
+
print(" ✅ No unique packages")
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def cmd_check(package_name):
|
|
201
|
+
"""Check if a package exists and where."""
|
|
202
|
+
print(f"\n🦦 mustel — check '{package_name}'\n")
|
|
203
|
+
|
|
204
|
+
current = sys.executable
|
|
205
|
+
|
|
206
|
+
# Check if importable in current
|
|
207
|
+
if is_importable(package_name):
|
|
208
|
+
print(f"✅ '{package_name}' is available in current Python")
|
|
209
|
+
return
|
|
210
|
+
|
|
211
|
+
print(f"❌ '{package_name}' is NOT in current Python ({current})\n")
|
|
212
|
+
|
|
213
|
+
# Search other Pythons
|
|
214
|
+
others = find_all_pythons()
|
|
215
|
+
found_in = []
|
|
216
|
+
|
|
217
|
+
for other in others:
|
|
218
|
+
packages = get_packages(other)
|
|
219
|
+
if package_name.lower() in packages:
|
|
220
|
+
found_in.append((other, packages[package_name.lower()]))
|
|
221
|
+
|
|
222
|
+
if found_in:
|
|
223
|
+
print("Found in:")
|
|
224
|
+
for path, version in found_in:
|
|
225
|
+
print(f" {path} -> {version}")
|
|
226
|
+
print(f"\nTo install: pip install {package_name}")
|
|
227
|
+
else:
|
|
228
|
+
print("Not found in any Python installation.")
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def cmd_updates():
|
|
232
|
+
"""Show outdated packages."""
|
|
233
|
+
print("\n🦦 mustel — updates\n")
|
|
234
|
+
|
|
235
|
+
current = sys.executable
|
|
236
|
+
print(f"Python: {current}\n")
|
|
237
|
+
print("⏳ Checking... (this takes 1-2 minutes)\n")
|
|
238
|
+
|
|
239
|
+
outdated = get_outdated(current)
|
|
240
|
+
|
|
241
|
+
if not outdated:
|
|
242
|
+
print("✅ All packages are up to date!")
|
|
243
|
+
return
|
|
244
|
+
|
|
245
|
+
print(f"📦 {len(outdated)} updates available:\n")
|
|
246
|
+
for name in sorted(outdated):
|
|
247
|
+
old, new = outdated[name]
|
|
248
|
+
print(f" {name}: {old} → {new}")
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def cmd_install(package_name):
|
|
252
|
+
"""Install a package using pip."""
|
|
253
|
+
print(f"\n🦦 mustel — install '{package_name}'\n")
|
|
254
|
+
|
|
255
|
+
current = sys.executable
|
|
256
|
+
print(f"Installing to: {current}\n")
|
|
257
|
+
|
|
258
|
+
# Check if already installed
|
|
259
|
+
packages = get_packages(current)
|
|
260
|
+
if package_name.lower() in packages:
|
|
261
|
+
version = packages[package_name.lower()]
|
|
262
|
+
print(f"⚠️ '{package_name}' is already installed (version {version})")
|
|
263
|
+
print(f"\nTo upgrade, run: pip install --upgrade {package_name}")
|
|
264
|
+
return
|
|
265
|
+
|
|
266
|
+
print(f"⏳ Installing {package_name}...\n")
|
|
267
|
+
|
|
268
|
+
# Run pip install (using subprocess.run so output shows in real-time)
|
|
269
|
+
result = subprocess.run(
|
|
270
|
+
[current, "-m", "pip", "install", package_name],
|
|
271
|
+
text=True
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
# Check if it worked
|
|
275
|
+
if result.returncode == 0:
|
|
276
|
+
print(f"\n✅ Successfully installed {package_name}!")
|
|
277
|
+
else:
|
|
278
|
+
print(f"\n❌ Failed to install {package_name}")
|
|
279
|
+
print(" Check the error message above.")
|
|
280
|
+
|
|
281
|
+
def cmd_help():
|
|
282
|
+
"""Show help."""
|
|
283
|
+
print("""
|
|
284
|
+
mustel — Python environment inspector
|
|
285
|
+
|
|
286
|
+
Commands:
|
|
287
|
+
mustel Show packages in current Python
|
|
288
|
+
mustel all Show all Python installations
|
|
289
|
+
mustel diff Compare packages across Pythons
|
|
290
|
+
mustel check X Check if package X exists
|
|
291
|
+
mustel install X Install package X
|
|
292
|
+
mustel updates Show outdated packages
|
|
293
|
+
mustel help Show this help
|
|
294
|
+
|
|
295
|
+
Tip: Run with different Python:
|
|
296
|
+
C:\\path\\python.exe -m mustel
|
|
297
|
+
""")
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
# ============================================================
|
|
301
|
+
# MAIN
|
|
302
|
+
# ============================================================
|
|
303
|
+
|
|
304
|
+
def main():
|
|
305
|
+
args = sys.argv[1:]
|
|
306
|
+
|
|
307
|
+
if not args:
|
|
308
|
+
cmd_list()
|
|
309
|
+
elif args[0] in ("help", "-h", "--help"):
|
|
310
|
+
cmd_help()
|
|
311
|
+
elif args[0] == "all":
|
|
312
|
+
cmd_all()
|
|
313
|
+
elif args[0] == "diff":
|
|
314
|
+
cmd_diff()
|
|
315
|
+
elif args[0] == "check" and len(args) > 1:
|
|
316
|
+
cmd_check(args[1])
|
|
317
|
+
elif args[0] == "updates":
|
|
318
|
+
cmd_updates()
|
|
319
|
+
elif args[0] == "install" and len(args) > 1:
|
|
320
|
+
cmd_install(args[1])
|
|
321
|
+
else:
|
|
322
|
+
print(f"Unknown command: {args[0]}")
|
|
323
|
+
cmd_help()
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
if __name__ == "__main__":
|
|
327
|
+
main()
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mustel
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Simple Python environment inspector - see what's installed across all your Python versions
|
|
5
|
+
Author: Raunak Nayak
|
|
6
|
+
Author-email: Ameya Kulkarni <acclaptop47@gmail.com>
|
|
7
|
+
License: Proprietary
|
|
8
|
+
Keywords: python,environment,packages,pip,inspector
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: Other/Proprietary License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Requires-Python: >=3.8
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
# mustel 🦦
|
|
28
|
+
|
|
29
|
+
A simple Python environment inspector. See what's installed across all your Python versions.
|
|
30
|
+
|
|
31
|
+
## Why?
|
|
32
|
+
|
|
33
|
+
Ever had this happen?
|
|
34
|
+
```
|
|
35
|
+
pip install numpy
|
|
36
|
+
import numpy # ❌ ModuleNotFoundError
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
That's because you have multiple Python versions, and `pip` installed it in a different one!
|
|
40
|
+
|
|
41
|
+
**mustel** helps you see exactly what's installed where.
|
|
42
|
+
|
|
43
|
+
## Install
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install mustel
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Usage
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
mustel # Show packages in current Python
|
|
53
|
+
mustel all # Show all Python installations
|
|
54
|
+
mustel diff # Compare packages across Pythons
|
|
55
|
+
mustel check X # Check if package X exists
|
|
56
|
+
mustel updates # Show outdated packages
|
|
57
|
+
mustel help # Show help
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Examples
|
|
61
|
+
|
|
62
|
+
### See all your Pythons
|
|
63
|
+
```
|
|
64
|
+
> mustel all
|
|
65
|
+
|
|
66
|
+
🦦 mustel — all pythons
|
|
67
|
+
|
|
68
|
+
Found 3 Python(s):
|
|
69
|
+
|
|
70
|
+
------------------------------------------------------------
|
|
71
|
+
★ Python 3.13.7 (current)
|
|
72
|
+
Path: C:\Users\...\Python313\python.exe
|
|
73
|
+
Packages: 151
|
|
74
|
+
|
|
75
|
+
Python 3.14.0
|
|
76
|
+
Path: C:\Users\...\Python314\python.exe
|
|
77
|
+
Packages: 8
|
|
78
|
+
------------------------------------------------------------
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Use with a specific Python
|
|
82
|
+
```bash
|
|
83
|
+
C:\Python314\python.exe -m mustel
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Why "mustel"?
|
|
87
|
+
|
|
88
|
+
Named after the **Mustelidae** family (otters, weasels, ferrets) - small but effective hunters that find things in hidden places! 🦦
|
|
89
|
+
|
|
90
|
+
## License
|
|
91
|
+
|
|
92
|
+
Proprietary - All Rights Reserved.
|
|
93
|
+
Copyright © 2025 Ameya Kulkarni, Raunak Nayak
|
|
94
|
+
|
|
95
|
+
See [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
mustel/__init__.py
|
|
5
|
+
mustel/__main__.py
|
|
6
|
+
mustel/main.py
|
|
7
|
+
mustel.egg-info/PKG-INFO
|
|
8
|
+
mustel.egg-info/SOURCES.txt
|
|
9
|
+
mustel.egg-info/dependency_links.txt
|
|
10
|
+
mustel.egg-info/entry_points.txt
|
|
11
|
+
mustel.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
mustel
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "mustel"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Simple Python environment inspector - see what's installed across all your Python versions"
|
|
9
|
+
requires-python = ">=3.8"
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
license = {text = "Proprietary"}
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Ameya Kulkarni", email = "acclaptop47@gmail.com"},
|
|
14
|
+
{name = "Raunak Nayak"},
|
|
15
|
+
]
|
|
16
|
+
keywords = ["python", "environment", "packages", "pip", "inspector"]
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Development Status :: 4 - Beta",
|
|
19
|
+
"Environment :: Console",
|
|
20
|
+
"Intended Audience :: Developers",
|
|
21
|
+
"License :: Other/Proprietary License",
|
|
22
|
+
"Operating System :: OS Independent",
|
|
23
|
+
"Programming Language :: Python :: 3",
|
|
24
|
+
"Programming Language :: Python :: 3.8",
|
|
25
|
+
"Programming Language :: Python :: 3.9",
|
|
26
|
+
"Programming Language :: Python :: 3.10",
|
|
27
|
+
"Programming Language :: Python :: 3.11",
|
|
28
|
+
"Programming Language :: Python :: 3.12",
|
|
29
|
+
"Programming Language :: Python :: 3.13",
|
|
30
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.scripts]
|
|
34
|
+
mustel = "mustel.main:main"
|
mustel-0.1.0/setup.cfg
ADDED