python-introspect 0.1.0__py3-none-any.whl
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.
- python_introspect/__init__.py +48 -0
- python_introspect/exceptions.py +21 -0
- python_introspect/signature_analyzer.py +1148 -0
- python_introspect/unified_parameter_analyzer.py +275 -0
- python_introspect-0.1.0.dist-info/METADATA +133 -0
- python_introspect-0.1.0.dist-info/RECORD +9 -0
- python_introspect-0.1.0.dist-info/WHEEL +5 -0
- python_introspect-0.1.0.dist-info/licenses/LICENSE +21 -0
- python_introspect-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
"""Unified parameter analysis interface for all parameter sources in OpenHCS TUI.
|
|
2
|
+
|
|
3
|
+
This module provides a single, consistent interface for analyzing parameters from:
|
|
4
|
+
- Functions and methods
|
|
5
|
+
- Dataclasses and their fields
|
|
6
|
+
- Nested dataclass structures
|
|
7
|
+
- Any callable or type with parameters
|
|
8
|
+
|
|
9
|
+
Replaces the fragmented approach of SignatureAnalyzer vs FieldIntrospector.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import inspect
|
|
13
|
+
import dataclasses
|
|
14
|
+
from typing import Dict, Union, Callable, Type, Any, Optional
|
|
15
|
+
from dataclasses import dataclass
|
|
16
|
+
|
|
17
|
+
from .signature_analyzer import SignatureAnalyzer, ParameterInfo
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class UnifiedParameterInfo:
|
|
22
|
+
"""Unified parameter information that works for all parameter sources."""
|
|
23
|
+
name: str
|
|
24
|
+
param_type: Type
|
|
25
|
+
default_value: Any
|
|
26
|
+
is_required: bool
|
|
27
|
+
description: Optional[str] = None
|
|
28
|
+
source_type: str = "unknown" # "function", "dataclass", "nested"
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def from_parameter_info(cls, param_info: ParameterInfo, source_type: str = "function") -> "UnifiedParameterInfo":
|
|
32
|
+
"""Convert from existing ParameterInfo to unified format."""
|
|
33
|
+
return cls(
|
|
34
|
+
name=param_info.name,
|
|
35
|
+
param_type=param_info.param_type,
|
|
36
|
+
default_value=param_info.default_value,
|
|
37
|
+
is_required=param_info.is_required,
|
|
38
|
+
description=param_info.description,
|
|
39
|
+
source_type=source_type
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class UnifiedParameterAnalyzer:
|
|
44
|
+
"""Single interface for analyzing parameters from any source.
|
|
45
|
+
|
|
46
|
+
This class provides a unified way to extract parameter information
|
|
47
|
+
from functions, dataclasses, and other parameter sources, ensuring
|
|
48
|
+
consistent behavior across the entire application.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
@staticmethod
|
|
52
|
+
def analyze(target: Union[Callable, Type, object], exclude_params: Optional[list] = None) -> Dict[str, UnifiedParameterInfo]:
|
|
53
|
+
"""Analyze parameters from any source.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
target: Function, method, dataclass type, or instance to analyze
|
|
57
|
+
exclude_params: Optional list of parameter names to exclude from analysis
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Dictionary mapping parameter names to UnifiedParameterInfo objects
|
|
61
|
+
|
|
62
|
+
Examples:
|
|
63
|
+
# Function analysis
|
|
64
|
+
param_info = UnifiedParameterAnalyzer.analyze(my_function)
|
|
65
|
+
|
|
66
|
+
# Dataclass analysis
|
|
67
|
+
param_info = UnifiedParameterAnalyzer.analyze(MyDataclass)
|
|
68
|
+
|
|
69
|
+
# Instance analysis
|
|
70
|
+
param_info = UnifiedParameterAnalyzer.analyze(my_instance)
|
|
71
|
+
|
|
72
|
+
# Instance analysis with exclusions (e.g., exclude 'func' from FunctionStep)
|
|
73
|
+
param_info = UnifiedParameterAnalyzer.analyze(step_instance, exclude_params=['func'])
|
|
74
|
+
"""
|
|
75
|
+
if target is None:
|
|
76
|
+
return {}
|
|
77
|
+
|
|
78
|
+
# Determine the type of target and route to appropriate analyzer
|
|
79
|
+
if inspect.isfunction(target) or inspect.ismethod(target):
|
|
80
|
+
result = UnifiedParameterAnalyzer._analyze_callable(target)
|
|
81
|
+
elif inspect.isclass(target):
|
|
82
|
+
if dataclasses.is_dataclass(target):
|
|
83
|
+
result = UnifiedParameterAnalyzer._analyze_dataclass_type(target)
|
|
84
|
+
else:
|
|
85
|
+
# CRITICAL FIX: For classes, use _analyze_object_instance with use_signature_defaults=True
|
|
86
|
+
# This traverses MRO to get all inherited parameters with signature defaults
|
|
87
|
+
# Create a dummy instance just to get the class hierarchy analyzed
|
|
88
|
+
try:
|
|
89
|
+
dummy_instance = target.__new__(target)
|
|
90
|
+
result = UnifiedParameterAnalyzer._analyze_object_instance(dummy_instance, use_signature_defaults=True)
|
|
91
|
+
except:
|
|
92
|
+
# If we can't create a dummy instance, fall back to just analyzing __init__
|
|
93
|
+
result = UnifiedParameterAnalyzer._analyze_callable(target.__init__)
|
|
94
|
+
elif dataclasses.is_dataclass(target):
|
|
95
|
+
# Instance of dataclass
|
|
96
|
+
result = UnifiedParameterAnalyzer._analyze_dataclass_instance(target)
|
|
97
|
+
else:
|
|
98
|
+
# Try to analyze as callable
|
|
99
|
+
if callable(target):
|
|
100
|
+
# Check if it has a __call__ method (callable object)
|
|
101
|
+
if hasattr(target, '__call__') and not inspect.isfunction(target):
|
|
102
|
+
# It's a callable object, analyze its __call__ method
|
|
103
|
+
result = UnifiedParameterAnalyzer._analyze_callable(target.__call__)
|
|
104
|
+
else:
|
|
105
|
+
result = UnifiedParameterAnalyzer._analyze_callable(target)
|
|
106
|
+
else:
|
|
107
|
+
# For regular object instances (like step instances), analyze their class constructor
|
|
108
|
+
result = UnifiedParameterAnalyzer._analyze_object_instance(target)
|
|
109
|
+
|
|
110
|
+
# Apply exclusions if specified
|
|
111
|
+
if exclude_params:
|
|
112
|
+
result = {name: info for name, info in result.items() if name not in exclude_params}
|
|
113
|
+
|
|
114
|
+
return result
|
|
115
|
+
|
|
116
|
+
@staticmethod
|
|
117
|
+
def _analyze_callable(callable_obj: Callable) -> Dict[str, UnifiedParameterInfo]:
|
|
118
|
+
"""Analyze a callable (function, method, etc.)."""
|
|
119
|
+
# Use existing SignatureAnalyzer for callables
|
|
120
|
+
param_info_dict = SignatureAnalyzer.analyze(callable_obj)
|
|
121
|
+
|
|
122
|
+
# Convert to unified format
|
|
123
|
+
unified_params = {}
|
|
124
|
+
for name, param_info in param_info_dict.items():
|
|
125
|
+
unified_params[name] = UnifiedParameterInfo.from_parameter_info(
|
|
126
|
+
param_info,
|
|
127
|
+
source_type="function"
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
return unified_params
|
|
131
|
+
|
|
132
|
+
@staticmethod
|
|
133
|
+
def _analyze_dataclass_type(dataclass_type: Type) -> Dict[str, UnifiedParameterInfo]:
|
|
134
|
+
"""Analyze a dataclass type using existing SignatureAnalyzer infrastructure."""
|
|
135
|
+
# CRITICAL FIX: Use existing SignatureAnalyzer._analyze_dataclass method
|
|
136
|
+
# which already handles all the docstring extraction properly
|
|
137
|
+
param_info_dict = SignatureAnalyzer._analyze_dataclass(dataclass_type)
|
|
138
|
+
|
|
139
|
+
# Convert to unified format
|
|
140
|
+
unified_params = {}
|
|
141
|
+
for name, param_info in param_info_dict.items():
|
|
142
|
+
unified_params[name] = UnifiedParameterInfo.from_parameter_info(
|
|
143
|
+
param_info,
|
|
144
|
+
source_type="dataclass"
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
return unified_params
|
|
148
|
+
|
|
149
|
+
@staticmethod
|
|
150
|
+
def _analyze_object_instance(instance: object, use_signature_defaults: bool = False) -> Dict[str, UnifiedParameterInfo]:
|
|
151
|
+
"""Analyze a regular object instance by examining its full inheritance hierarchy.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
instance: Object instance to analyze
|
|
155
|
+
use_signature_defaults: If True, use signature defaults instead of instance values
|
|
156
|
+
"""
|
|
157
|
+
# Use MRO to get all constructor parameters from the inheritance chain
|
|
158
|
+
instance_class = type(instance)
|
|
159
|
+
all_params = {}
|
|
160
|
+
|
|
161
|
+
# Traverse MRO from most specific to most general (like dual-axis resolver)
|
|
162
|
+
for cls in instance_class.__mro__:
|
|
163
|
+
if cls == object:
|
|
164
|
+
continue
|
|
165
|
+
|
|
166
|
+
# Skip classes without custom __init__
|
|
167
|
+
if not hasattr(cls, '__init__') or cls.__init__ == object.__init__:
|
|
168
|
+
continue
|
|
169
|
+
|
|
170
|
+
try:
|
|
171
|
+
# Analyze this class's constructor
|
|
172
|
+
class_params = UnifiedParameterAnalyzer._analyze_callable(cls.__init__)
|
|
173
|
+
|
|
174
|
+
# Remove 'self' parameter
|
|
175
|
+
if 'self' in class_params:
|
|
176
|
+
del class_params['self']
|
|
177
|
+
|
|
178
|
+
# Special handling for **kwargs - if we see 'kwargs', skip this class
|
|
179
|
+
# and let parent classes provide the actual parameters
|
|
180
|
+
if 'kwargs' in class_params and len(class_params) <= 2:
|
|
181
|
+
# This class uses **kwargs, skip it and let parent classes define parameters
|
|
182
|
+
continue
|
|
183
|
+
|
|
184
|
+
# Add parameters that haven't been seen yet (most specific wins)
|
|
185
|
+
for param_name, param_info in class_params.items():
|
|
186
|
+
if param_name not in all_params and param_name != 'kwargs':
|
|
187
|
+
# CRITICAL FIX: For reset functionality, use signature defaults instead of instance values
|
|
188
|
+
if use_signature_defaults:
|
|
189
|
+
default_value = param_info.default_value
|
|
190
|
+
else:
|
|
191
|
+
# Get current value from instance if it exists
|
|
192
|
+
default_value = getattr(instance, param_name, param_info.default_value)
|
|
193
|
+
|
|
194
|
+
# Create parameter info with appropriate default value
|
|
195
|
+
all_params[param_name] = UnifiedParameterInfo(
|
|
196
|
+
name=param_name,
|
|
197
|
+
param_type=param_info.param_type,
|
|
198
|
+
default_value=default_value,
|
|
199
|
+
is_required=param_info.is_required,
|
|
200
|
+
description=param_info.description, # CRITICAL FIX: Include description
|
|
201
|
+
source_type="object_instance"
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
except Exception:
|
|
205
|
+
# Skip classes that can't be analyzed - this is legitimate since some classes
|
|
206
|
+
# in MRO might not have analyzable constructors (e.g., ABC, object)
|
|
207
|
+
continue
|
|
208
|
+
|
|
209
|
+
return all_params
|
|
210
|
+
|
|
211
|
+
@staticmethod
|
|
212
|
+
def _analyze_dataclass_instance(instance: object) -> Dict[str, UnifiedParameterInfo]:
|
|
213
|
+
"""Analyze a dataclass instance."""
|
|
214
|
+
# Get the type and analyze it
|
|
215
|
+
dataclass_type = type(instance)
|
|
216
|
+
unified_params = UnifiedParameterAnalyzer._analyze_dataclass_type(dataclass_type)
|
|
217
|
+
|
|
218
|
+
# Update default values with current instance values
|
|
219
|
+
for name, param_info in unified_params.items():
|
|
220
|
+
if hasattr(instance, name):
|
|
221
|
+
# For regular dataclasses, use normal getattr
|
|
222
|
+
current_value = getattr(instance, name)
|
|
223
|
+
|
|
224
|
+
# Create new UnifiedParameterInfo with current value as default
|
|
225
|
+
unified_params[name] = UnifiedParameterInfo(
|
|
226
|
+
name=param_info.name,
|
|
227
|
+
param_type=param_info.param_type,
|
|
228
|
+
default_value=current_value,
|
|
229
|
+
is_required=param_info.is_required,
|
|
230
|
+
description=param_info.description,
|
|
231
|
+
source_type="dataclass_instance"
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
return unified_params
|
|
235
|
+
|
|
236
|
+
@staticmethod
|
|
237
|
+
def analyze_nested(target: Union[Callable, Type, object], parent_info: Dict[str, UnifiedParameterInfo] = None) -> Dict[str, UnifiedParameterInfo]:
|
|
238
|
+
"""Analyze parameters with nested dataclass support.
|
|
239
|
+
|
|
240
|
+
This method provides enhanced analysis that can handle nested dataclasses
|
|
241
|
+
and maintain parent context information.
|
|
242
|
+
|
|
243
|
+
Args:
|
|
244
|
+
target: The target to analyze
|
|
245
|
+
parent_info: Optional parent parameter information for context
|
|
246
|
+
|
|
247
|
+
Returns:
|
|
248
|
+
Dictionary of unified parameter information with nested support
|
|
249
|
+
"""
|
|
250
|
+
base_params = UnifiedParameterAnalyzer.analyze(target)
|
|
251
|
+
|
|
252
|
+
# For each parameter, check if it's a nested dataclass
|
|
253
|
+
enhanced_params = {}
|
|
254
|
+
for name, param_info in base_params.items():
|
|
255
|
+
enhanced_params[name] = param_info
|
|
256
|
+
|
|
257
|
+
# If this parameter is a dataclass, mark it as having nested structure
|
|
258
|
+
if dataclasses.is_dataclass(param_info.param_type):
|
|
259
|
+
# Update source type to indicate nesting capability
|
|
260
|
+
enhanced_params[name] = UnifiedParameterInfo(
|
|
261
|
+
name=param_info.name,
|
|
262
|
+
param_type=param_info.param_type,
|
|
263
|
+
default_value=param_info.default_value,
|
|
264
|
+
is_required=param_info.is_required,
|
|
265
|
+
description=param_info.description,
|
|
266
|
+
source_type=f"{param_info.source_type}_nested"
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
return enhanced_params
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
# Backward compatibility aliases
|
|
273
|
+
# These allow existing code to continue working while migration happens
|
|
274
|
+
ParameterAnalyzer = UnifiedParameterAnalyzer
|
|
275
|
+
analyze_parameters = UnifiedParameterAnalyzer.analyze
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: python-introspect
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Pure Python introspection toolkit for function signatures, dataclasses, and type hints
|
|
5
|
+
Author-email: Tristan Simas <tristan.simas@mail.mcgill.ca>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/OpenHCSDev/python-introspect
|
|
8
|
+
Project-URL: Repository, https://github.com/OpenHCSDev/python-introspect
|
|
9
|
+
Project-URL: Issues, https://github.com/OpenHCSDev/python-introspect/issues
|
|
10
|
+
Keywords: introspection,reflection,signature,dataclass,type-hints,docstring
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Classifier: Topic :: Utilities
|
|
21
|
+
Requires-Python: >=3.9
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
26
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
27
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
28
|
+
Requires-Dist: black>=23.0; extra == "dev"
|
|
29
|
+
Requires-Dist: mypy>=1.0; extra == "dev"
|
|
30
|
+
Provides-Extra: docs
|
|
31
|
+
Requires-Dist: mkdocs>=1.5.0; extra == "docs"
|
|
32
|
+
Requires-Dist: mkdocs-material>=9.0.0; extra == "docs"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# python-introspect
|
|
36
|
+
|
|
37
|
+
**Pure Python introspection toolkit for function signatures, dataclasses, and type hints**
|
|
38
|
+
|
|
39
|
+
[](https://www.python.org/downloads/)
|
|
40
|
+
[](https://opensource.org/licenses/MIT)
|
|
41
|
+
[](https://github.com/trissim/python-introspect/actions/workflows/ci.yml)
|
|
42
|
+
[](https://badge.fury.io/py/python-introspect)
|
|
43
|
+
|
|
44
|
+
## Features
|
|
45
|
+
|
|
46
|
+
- 🔍 **Function/Method Signature Analysis** - Extract parameter info from any callable
|
|
47
|
+
- 📦 **Dataclass Field Extraction** - Analyze dataclass fields and types
|
|
48
|
+
- 📝 **Docstring Parsing** - Extract and parse docstrings (Google, NumPy, Sphinx styles)
|
|
49
|
+
- 🏷️ **Type Hint Resolution** - Resolve complex type hints and annotations
|
|
50
|
+
- 🎯 **Unified API** - Single interface for all parameter sources
|
|
51
|
+
- 🚀 **Pure Python** - No external dependencies, pure stdlib
|
|
52
|
+
|
|
53
|
+
## Installation
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pip install python-introspect
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Quick Start
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from python_introspect import SignatureAnalyzer
|
|
63
|
+
|
|
64
|
+
def example_function(name: str, age: int = 25, *, active: bool = True):
|
|
65
|
+
"""
|
|
66
|
+
Example function with parameters.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
name: The person's name
|
|
70
|
+
age: The person's age
|
|
71
|
+
active: Whether the person is active
|
|
72
|
+
"""
|
|
73
|
+
pass
|
|
74
|
+
|
|
75
|
+
# Analyze the function
|
|
76
|
+
analyzer = SignatureAnalyzer()
|
|
77
|
+
params = analyzer.analyze_function(example_function)
|
|
78
|
+
|
|
79
|
+
for param in params:
|
|
80
|
+
print(f"{param.name}: {param.annotation} = {param.default}")
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Use Cases
|
|
84
|
+
|
|
85
|
+
- **Form Generation** - Generate UI forms from function signatures
|
|
86
|
+
- **API Documentation** - Auto-generate API docs from code
|
|
87
|
+
- **Configuration Validation** - Validate config against function parameters
|
|
88
|
+
- **Dynamic UI** - Build dynamic UIs based on function signatures
|
|
89
|
+
- **Parameter Analysis** - Analyze and validate function parameters
|
|
90
|
+
|
|
91
|
+
## Documentation
|
|
92
|
+
|
|
93
|
+
Full documentation available at: https://github.com/trissim/python-introspect
|
|
94
|
+
|
|
95
|
+
## Development
|
|
96
|
+
|
|
97
|
+
### Setup
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# Clone the repository
|
|
101
|
+
git clone https://github.com/trissim/python-introspect.git
|
|
102
|
+
cd python-introspect
|
|
103
|
+
|
|
104
|
+
# Create virtual environment
|
|
105
|
+
python -m venv venv
|
|
106
|
+
source venv/bin/activate # On Windows: venv\Scripts\activate
|
|
107
|
+
|
|
108
|
+
# Install in development mode with dev dependencies
|
|
109
|
+
pip install -e ".[dev]"
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Running Tests
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
# Run all tests
|
|
116
|
+
pytest tests/
|
|
117
|
+
|
|
118
|
+
# Run with coverage
|
|
119
|
+
pytest tests/ --cov=python_introspect --cov-report=term --cov-report=html
|
|
120
|
+
|
|
121
|
+
# Run linting and formatting checks
|
|
122
|
+
ruff check src/ tests/
|
|
123
|
+
black --check src/ tests/
|
|
124
|
+
mypy src/python_introspect/
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Contributing
|
|
128
|
+
|
|
129
|
+
Contributions welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
130
|
+
|
|
131
|
+
## Credits
|
|
132
|
+
|
|
133
|
+
Developed by Tristan Simas as part of the OpenHCS project.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
python_introspect/__init__.py,sha256=4b7Hho24-R0BwWnllBcn_oIi1Im2wlJfWyd_56kYRIc,1069
|
|
2
|
+
python_introspect/exceptions.py,sha256=TG8Vo2JdArBbL8hlHmfmt31LtEKtGAuFEh2Rh07DQHs,488
|
|
3
|
+
python_introspect/signature_analyzer.py,sha256=bjEnkVpsBm8wdEzpuVfki95azLf_ylbLAlRigXzZT08,51072
|
|
4
|
+
python_introspect/unified_parameter_analyzer.py,sha256=npsl7FMyUSg4JjV56PMOHQzqo2z0ZldvR7ZTSgAvQjE,12156
|
|
5
|
+
python_introspect-0.1.0.dist-info/licenses/LICENSE,sha256=xagEoeTAj1WT64RmyR3E6HH-eTGdgXN6gqPMUUt7L_Y,1070
|
|
6
|
+
python_introspect-0.1.0.dist-info/METADATA,sha256=2ahrEP_hkwqkjePXy3--4ZUIcQPhCUUtporTZXGCPas,4372
|
|
7
|
+
python_introspect-0.1.0.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
|
|
8
|
+
python_introspect-0.1.0.dist-info/top_level.txt,sha256=TZq9Yj1LeXI7A96PDqf7ZbWGSB1zLlQDww0esC91bwY,18
|
|
9
|
+
python_introspect-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Tristan Simas
|
|
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.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
python_introspect
|