0
# Utilities
1
2
Utility functions for package version detection, version comparison, and environment detection. These functions provide the building blocks used by the reporting system.
3
4
## Capabilities
5
6
### Constants
7
8
```python { .api }
9
MODULE_NOT_FOUND = 'Module not found'
10
MODULE_TROUBLE = 'Trouble importing'
11
VERSION_NOT_FOUND = 'Version unknown'
12
```
13
14
### Version Detection
15
16
Get version information for any installed package using multiple detection strategies.
17
18
```python { .api }
19
def get_version(module: str | ModuleType) -> tuple[str, str | None]:
20
"""
21
Get the version of a module by passing the package or its name.
22
23
This function tries multiple strategies to detect version information:
24
1. importlib.metadata (preferred)
25
2. Common version attributes (__version__, version)
26
3. Known package-specific version locations
27
4. Package-specific version methods
28
29
Parameters:
30
- module (str | ModuleType): Name of module to import or the module itself
31
32
Returns:
33
- tuple[str, str | None]: (package_name, version_string)
34
- version_string can be None if version cannot be determined
35
- Returns MODULE_NOT_FOUND if module cannot be imported
36
- Returns MODULE_TROUBLE if module import fails with error
37
- Returns VERSION_NOT_FOUND if module loads but version cannot be found
38
"""
39
```
40
41
### Version Comparison
42
43
Compare version strings to check if a package meets minimum version requirements.
44
45
```python { .api }
46
def meets_version(version: str, meets: str) -> bool:
47
"""
48
Check if a version string meets a minimum version requirement.
49
50
This is a simplified version comparison tool. For robust version
51
comparison, consider using the 'packaging' library.
52
53
Parameters:
54
- version (str): Version string to check (e.g., '1.2.3')
55
- meets (str): Required minimum version (e.g., '1.2.0')
56
57
Returns:
58
- bool: True if version >= meets, False otherwise
59
60
Raises:
61
- ValueError: If version strings have more than 3 parts
62
- AssertionError: If versions are not comparable
63
64
Examples:
65
>>> meets_version('1.2.3', '1.2.0')
66
True
67
>>> meets_version('1.1.9', '1.2.0')
68
False
69
"""
70
71
def version_tuple(v: str) -> tuple[int, ...]:
72
"""
73
Convert a version string to a tuple of integers.
74
75
Non-numeric version components are converted to 0.
76
Version strings shorter than 3 parts are padded with 0.
77
78
Parameters:
79
- v (str): Version string (e.g., '1.2.3dev0')
80
81
Returns:
82
- tuple[int, ...]: Tuple of integers (e.g., (1, 2, 3))
83
84
Raises:
85
- ValueError: If version string has more than 3 parts
86
87
Examples:
88
>>> version_tuple('1.2.3')
89
(1, 2, 3)
90
>>> version_tuple('1.2.3dev0')
91
(1, 2, 0)
92
>>> version_tuple('1.2')
93
(1, 2, 0)
94
"""
95
```
96
97
### Environment Detection
98
99
Detect the Python execution environment to enable environment-specific formatting.
100
101
```python { .api }
102
def in_ipython() -> bool:
103
"""
104
Check if running in an IPython environment.
105
106
Returns:
107
- bool: True if in IPython, False otherwise
108
"""
109
110
def in_ipykernel() -> bool:
111
"""
112
Check if running in an ipykernel (most likely Jupyter) environment.
113
114
Note: This detects if using an ipykernel but cannot distinguish between
115
Jupyter Notebook, JupyterLab, QtConsole, or other frontends.
116
117
Returns:
118
- bool: True if using an ipykernel, False otherwise
119
"""
120
```
121
122
### Standard Library Detection
123
124
Get information about Python's standard library modules for filtering purposes.
125
126
```python { .api }
127
def get_standard_lib_modules() -> set[str]:
128
"""
129
Return a set of names of all modules in the standard library.
130
131
This is used internally to filter out standard library modules from
132
package reports and import tracking.
133
134
Returns:
135
- set[str]: Set of standard library module names
136
"""
137
```
138
139
### Distribution Dependencies
140
141
Get dependency information for installed packages using distribution metadata.
142
143
```python { .api }
144
def get_distribution_dependencies(dist_name: str) -> list[str]:
145
"""
146
Get the dependencies of a specified package distribution.
147
148
Uses importlib.metadata to read distribution metadata and extract
149
required dependencies. This is used internally by AutoReport to
150
automatically include package dependencies in reports.
151
152
Parameters:
153
- dist_name (str): Name of the package distribution
154
155
Returns:
156
- list[str]: List of dependency package names
157
158
Raises:
159
- PackageNotFoundError: If the distribution is not found
160
"""
161
```
162
163
## Usage Examples
164
165
### Version Detection
166
167
```python
168
import scooby
169
import numpy
170
171
# Get version by module name
172
name, version = scooby.get_version('numpy')
173
print(f"{name}: {version}") # numpy: 1.21.0
174
175
# Get version by module object
176
name, version = scooby.get_version(numpy)
177
print(f"{name}: {version}") # numpy: 1.21.0
178
179
# Handle missing packages
180
name, version = scooby.get_version('nonexistent_package')
181
print(f"{name}: {version}") # nonexistent_package: Module not found
182
183
# Handle packages without version info
184
name, version = scooby.get_version('some_local_module')
185
print(f"{name}: {version}") # some_local_module: Version unknown
186
187
# Check against constants
188
import scooby
189
from scooby.report import MODULE_NOT_FOUND
190
191
name, version = scooby.get_version('missing_pkg')
192
if version == MODULE_NOT_FOUND:
193
print(f"Package {name} is not installed")
194
```
195
196
### Version Comparison
197
198
```python
199
import scooby
200
201
# Check if installed version meets requirements
202
name, version = scooby.get_version('numpy')
203
if version and scooby.meets_version(version, '1.19.0'):
204
print("NumPy version is sufficient")
205
else:
206
print("NumPy version is too old or not installed")
207
208
# Version comparison examples
209
print(scooby.meets_version('1.2.3', '1.2.0')) # True
210
print(scooby.meets_version('1.1.9', '1.2.0')) # False
211
print(scooby.meets_version('2.0.0', '1.9.9')) # True
212
213
# Convert version strings to tuples for custom comparison
214
v1 = scooby.version_tuple('1.2.3dev0') # (1, 2, 0)
215
v2 = scooby.version_tuple('1.2.3') # (1, 2, 3)
216
print(v1 < v2) # True
217
```
218
219
### Environment Detection
220
221
```python
222
import scooby
223
224
# Detect execution environment
225
if scooby.in_ipykernel():
226
print("Running in Jupyter (or similar ipykernel environment)")
227
# Use HTML output
228
report = scooby.Report()
229
display(report) # Will use _repr_html_()
230
elif scooby.in_ipython():
231
print("Running in IPython")
232
# Use enhanced IPython features
233
report = scooby.Report()
234
print(report)
235
else:
236
print("Running in standard Python")
237
# Use plain text output
238
report = scooby.Report()
239
print(report)
240
```
241
242
### Standard Library Filtering
243
244
```python
245
import scooby
246
247
# Get all standard library modules
248
stdlib_modules = scooby.get_standard_lib_modules()
249
print(f"Standard library contains {len(stdlib_modules)} modules")
250
251
# Check if a module is in standard library
252
def is_third_party(module_name):
253
return module_name not in stdlib_modules
254
255
print(is_third_party('os')) # False (standard library)
256
print(is_third_party('numpy')) # True (third party)
257
print(is_third_party('json')) # False (standard library)
258
```
259
260
### Distribution Dependencies
261
262
```python
263
from scooby.report import get_distribution_dependencies
264
from importlib.metadata import PackageNotFoundError
265
266
# Get dependencies for a package
267
try:
268
deps = get_distribution_dependencies('matplotlib')
269
print(f"matplotlib dependencies: {deps}")
270
# Example output: ['numpy', 'python-dateutil', 'pyparsing', ...]
271
except PackageNotFoundError:
272
print("Package not found")
273
274
# Use in combination with version checking
275
def analyze_package_ecosystem(package_name):
276
"""Analyze a package and its entire dependency tree."""
277
try:
278
# Get the main package version
279
name, version = scooby.get_version(package_name)
280
print(f"Main package: {name} {version}")
281
282
# Get its dependencies
283
deps = get_distribution_dependencies(package_name)
284
print(f"Dependencies ({len(deps)}): {', '.join(deps)}")
285
286
# Check versions of all dependencies
287
for dep in deps:
288
dep_name, dep_version = scooby.get_version(dep)
289
print(f" {dep_name}: {dep_version}")
290
291
except PackageNotFoundError:
292
print(f"Package {package_name} not found")
293
294
# Analyze an entire ecosystem
295
analyze_package_ecosystem('matplotlib')
296
```
297
298
### Comprehensive Package Analysis
299
300
```python
301
import scooby
302
303
def analyze_package(package_name):
304
"""Comprehensive analysis of a package."""
305
name, version = scooby.get_version(package_name)
306
307
print(f"Package: {name}")
308
print(f"Version: {version}")
309
310
if version and version not in ['Module not found', 'Trouble importing', 'Version unknown']:
311
# Check version requirements
312
if scooby.meets_version(version, '1.0.0'):
313
print("β Meets minimum version 1.0.0")
314
else:
315
print("β Below minimum version 1.0.0")
316
317
# Show version tuple
318
v_tuple = scooby.version_tuple(version)
319
print(f"Version tuple: {v_tuple}")
320
321
# Check if it's third-party
322
stdlib_modules = scooby.get_standard_lib_modules()
323
if name in stdlib_modules:
324
print("π¦ Standard library module")
325
else:
326
print("π§ Third-party package")
327
328
# Analyze various packages
329
for pkg in ['numpy', 'os', 'requests', 'nonexistent']:
330
analyze_package(pkg)
331
print()
332
```
333
334
### Custom Version Checking
335
336
```python
337
import scooby
338
339
def check_requirements(requirements):
340
"""
341
Check if installed packages meet version requirements.
342
343
Args:
344
requirements (dict): {package_name: min_version}
345
346
Returns:
347
dict: {package_name: (installed_version, meets_requirement)}
348
"""
349
import scooby
350
from scooby.report import MODULE_NOT_FOUND, MODULE_TROUBLE, VERSION_NOT_FOUND
351
352
results = {}
353
354
for package, min_version in requirements.items():
355
name, installed = scooby.get_version(package)
356
357
if installed in [MODULE_NOT_FOUND, MODULE_TROUBLE, VERSION_NOT_FOUND]:
358
meets_req = False
359
else:
360
meets_req = scooby.meets_version(installed, min_version)
361
362
results[name] = (installed, meets_req)
363
364
return results
365
366
# Check project requirements
367
requirements = {
368
'numpy': '1.19.0',
369
'pandas': '1.3.0',
370
'matplotlib': '3.3.0'
371
}
372
373
results = check_requirements(requirements)
374
for package, (version, meets) in results.items():
375
status = "β" if meets else "β"
376
print(f"{status} {package}: {version}")
377
```