pyconvexity 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.
Potentially problematic release.
This version of pyconvexity might be problematic. Click here for more details.
- pyconvexity/__init__.py +120 -0
- pyconvexity/_version.py +2 -0
- pyconvexity/core/__init__.py +64 -0
- pyconvexity/core/database.py +314 -0
- pyconvexity/core/errors.py +100 -0
- pyconvexity/core/types.py +306 -0
- pyconvexity/models/__init__.py +36 -0
- pyconvexity/models/attributes.py +383 -0
- pyconvexity/models/components.py +464 -0
- pyconvexity/models/network.py +426 -0
- pyconvexity/validation/__init__.py +17 -0
- pyconvexity/validation/rules.py +301 -0
- pyconvexity-0.1.0.dist-info/METADATA +135 -0
- pyconvexity-0.1.0.dist-info/RECORD +16 -0
- pyconvexity-0.1.0.dist-info/WHEEL +5 -0
- pyconvexity-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Validation rules and operations for PyConvexity.
|
|
3
|
+
|
|
4
|
+
Provides validation logic for component attributes, data types, and timeseries alignment.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import sqlite3
|
|
8
|
+
import json
|
|
9
|
+
import logging
|
|
10
|
+
from typing import Dict, Any, Optional, List
|
|
11
|
+
|
|
12
|
+
from pyconvexity.core.types import (
|
|
13
|
+
ValidationRule, StaticValue, TimeseriesPoint, TimePeriod, TimeseriesValidationResult
|
|
14
|
+
)
|
|
15
|
+
from pyconvexity.core.errors import (
|
|
16
|
+
ValidationError, InvalidDataType
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def get_validation_rule(
|
|
23
|
+
conn: sqlite3.Connection,
|
|
24
|
+
component_type: str,
|
|
25
|
+
attribute_name: str
|
|
26
|
+
) -> ValidationRule:
|
|
27
|
+
"""
|
|
28
|
+
Get validation rule for a specific component type and attribute.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
conn: Database connection
|
|
32
|
+
component_type: Type of component (e.g., "BUS", "GENERATOR")
|
|
33
|
+
attribute_name: Name of the attribute
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
ValidationRule object with all validation information
|
|
37
|
+
|
|
38
|
+
Raises:
|
|
39
|
+
ValidationError: If no validation rule is found
|
|
40
|
+
"""
|
|
41
|
+
cursor = conn.execute("""
|
|
42
|
+
SELECT component_type, attribute_name, data_type, unit, default_value, allowed_storage_types,
|
|
43
|
+
is_required, is_input, description
|
|
44
|
+
FROM attribute_validation_rules
|
|
45
|
+
WHERE component_type = ? AND attribute_name = ?
|
|
46
|
+
""", (component_type, attribute_name))
|
|
47
|
+
|
|
48
|
+
row = cursor.fetchone()
|
|
49
|
+
if not row:
|
|
50
|
+
raise ValidationError(f"No validation rule found for {component_type}.{attribute_name}")
|
|
51
|
+
|
|
52
|
+
allowed_storage_types = row[5]
|
|
53
|
+
allows_static = allowed_storage_types in ("static", "static_or_timeseries")
|
|
54
|
+
allows_timeseries = allowed_storage_types in ("timeseries", "static_or_timeseries")
|
|
55
|
+
|
|
56
|
+
# Parse default value
|
|
57
|
+
default_value = None
|
|
58
|
+
if row[4]: # default_value_string
|
|
59
|
+
default_value = parse_default_value(row[4])
|
|
60
|
+
|
|
61
|
+
return ValidationRule(
|
|
62
|
+
component_type=row[0],
|
|
63
|
+
attribute_name=row[1],
|
|
64
|
+
data_type=row[2],
|
|
65
|
+
unit=row[3],
|
|
66
|
+
default_value_string=row[4],
|
|
67
|
+
allowed_storage_types=allowed_storage_types,
|
|
68
|
+
allows_static=allows_static,
|
|
69
|
+
allows_timeseries=allows_timeseries,
|
|
70
|
+
is_required=bool(row[6]),
|
|
71
|
+
is_input=bool(row[7]),
|
|
72
|
+
description=row[8],
|
|
73
|
+
default_value=default_value
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def list_validation_rules(
|
|
78
|
+
conn: sqlite3.Connection,
|
|
79
|
+
component_type: str
|
|
80
|
+
) -> List[ValidationRule]:
|
|
81
|
+
"""
|
|
82
|
+
List validation rules for a component type.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
conn: Database connection
|
|
86
|
+
component_type: Type of component
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
List of ValidationRule objects
|
|
90
|
+
"""
|
|
91
|
+
cursor = conn.execute("""
|
|
92
|
+
SELECT component_type, attribute_name, data_type, unit, default_value, allowed_storage_types,
|
|
93
|
+
is_required, is_input, description
|
|
94
|
+
FROM attribute_validation_rules
|
|
95
|
+
WHERE component_type = ?
|
|
96
|
+
ORDER BY attribute_name
|
|
97
|
+
""", (component_type,))
|
|
98
|
+
|
|
99
|
+
rules = []
|
|
100
|
+
for row in cursor.fetchall():
|
|
101
|
+
allowed_storage_types = row[5]
|
|
102
|
+
allows_static = allowed_storage_types in ("static", "static_or_timeseries")
|
|
103
|
+
allows_timeseries = allowed_storage_types in ("timeseries", "static_or_timeseries")
|
|
104
|
+
|
|
105
|
+
# Parse default value
|
|
106
|
+
default_value = None
|
|
107
|
+
if row[4]: # default_value_string
|
|
108
|
+
default_value = parse_default_value(row[4])
|
|
109
|
+
|
|
110
|
+
rules.append(ValidationRule(
|
|
111
|
+
component_type=row[0],
|
|
112
|
+
attribute_name=row[1],
|
|
113
|
+
data_type=row[2],
|
|
114
|
+
unit=row[3],
|
|
115
|
+
default_value_string=row[4],
|
|
116
|
+
allowed_storage_types=allowed_storage_types,
|
|
117
|
+
allows_static=allows_static,
|
|
118
|
+
allows_timeseries=allows_timeseries,
|
|
119
|
+
is_required=bool(row[6]),
|
|
120
|
+
is_input=bool(row[7]),
|
|
121
|
+
description=row[8],
|
|
122
|
+
default_value=default_value
|
|
123
|
+
))
|
|
124
|
+
|
|
125
|
+
return rules
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def get_all_validation_rules(conn: sqlite3.Connection) -> Dict[str, Any]:
|
|
129
|
+
"""
|
|
130
|
+
Get all validation rules from the database.
|
|
131
|
+
This replaces the need to load the entire JSON file into memory.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
conn: Database connection
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
Dictionary mapping component types to their validation rules
|
|
138
|
+
"""
|
|
139
|
+
try:
|
|
140
|
+
cursor = conn.execute("""
|
|
141
|
+
SELECT component_type, attribute_name, data_type, unit, default_value, allowed_storage_types,
|
|
142
|
+
is_required, is_input, description
|
|
143
|
+
FROM attribute_validation_rules
|
|
144
|
+
""")
|
|
145
|
+
|
|
146
|
+
rules = {}
|
|
147
|
+
for row in cursor.fetchall():
|
|
148
|
+
component_type = row[0]
|
|
149
|
+
attribute_name = row[1]
|
|
150
|
+
data_type = row[2]
|
|
151
|
+
unit = row[3]
|
|
152
|
+
default_value = row[4]
|
|
153
|
+
allowed_storage_types = row[5]
|
|
154
|
+
is_required = bool(row[6])
|
|
155
|
+
is_input = bool(row[7])
|
|
156
|
+
description = row[8]
|
|
157
|
+
|
|
158
|
+
if component_type not in rules:
|
|
159
|
+
rules[component_type] = {}
|
|
160
|
+
|
|
161
|
+
rules[component_type][attribute_name] = {
|
|
162
|
+
'data_type': data_type,
|
|
163
|
+
'unit': unit,
|
|
164
|
+
'default_value': default_value,
|
|
165
|
+
'allowed_storage_types': allowed_storage_types,
|
|
166
|
+
'is_required': is_required,
|
|
167
|
+
'is_input': is_input,
|
|
168
|
+
'description': description
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return rules
|
|
172
|
+
except Exception as e:
|
|
173
|
+
logger.error(f"Error getting all validation rules: {e}")
|
|
174
|
+
return {}
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def validate_static_value(value: StaticValue, rule: ValidationRule) -> None:
|
|
178
|
+
"""
|
|
179
|
+
Validate static value against rule.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
value: StaticValue to validate
|
|
183
|
+
rule: ValidationRule to validate against
|
|
184
|
+
|
|
185
|
+
Raises:
|
|
186
|
+
InvalidDataType: If value type doesn't match rule
|
|
187
|
+
"""
|
|
188
|
+
value_type = value.data_type()
|
|
189
|
+
|
|
190
|
+
if value_type != rule.data_type:
|
|
191
|
+
raise InvalidDataType(expected=rule.data_type, actual=value_type)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def validate_timeseries_alignment(
|
|
195
|
+
conn: sqlite3.Connection,
|
|
196
|
+
network_id: int,
|
|
197
|
+
timeseries: List[TimeseriesPoint]
|
|
198
|
+
) -> TimeseriesValidationResult:
|
|
199
|
+
"""
|
|
200
|
+
Validate timeseries alignment with network periods.
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
conn: Database connection
|
|
204
|
+
network_id: Network ID
|
|
205
|
+
timeseries: List of timeseries points to validate
|
|
206
|
+
|
|
207
|
+
Returns:
|
|
208
|
+
TimeseriesValidationResult with validation details
|
|
209
|
+
"""
|
|
210
|
+
# Get network time periods
|
|
211
|
+
from pyconvexity.models.network import get_network_time_periods
|
|
212
|
+
network_periods = get_network_time_periods(conn, network_id)
|
|
213
|
+
network_period_indices = {p.period_index for p in network_periods}
|
|
214
|
+
|
|
215
|
+
# Get provided period indices
|
|
216
|
+
provided_period_indices = {p.period_index for p in timeseries}
|
|
217
|
+
|
|
218
|
+
# Find missing and extra periods
|
|
219
|
+
missing_periods = list(network_period_indices - provided_period_indices)
|
|
220
|
+
extra_periods = list(provided_period_indices - network_period_indices)
|
|
221
|
+
|
|
222
|
+
is_valid = len(missing_periods) == 0 and len(extra_periods) == 0
|
|
223
|
+
|
|
224
|
+
return TimeseriesValidationResult(
|
|
225
|
+
is_valid=is_valid,
|
|
226
|
+
missing_periods=missing_periods,
|
|
227
|
+
extra_periods=extra_periods,
|
|
228
|
+
total_network_periods=len(network_periods),
|
|
229
|
+
provided_periods=len(timeseries)
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def parse_default_value(s: str) -> Optional[StaticValue]:
|
|
234
|
+
"""
|
|
235
|
+
Parse default value string.
|
|
236
|
+
|
|
237
|
+
Args:
|
|
238
|
+
s: String representation of default value
|
|
239
|
+
|
|
240
|
+
Returns:
|
|
241
|
+
StaticValue object or None if parsing fails
|
|
242
|
+
"""
|
|
243
|
+
# Try to parse as JSON first
|
|
244
|
+
try:
|
|
245
|
+
value = json.loads(s)
|
|
246
|
+
if isinstance(value, float):
|
|
247
|
+
return StaticValue(value)
|
|
248
|
+
elif isinstance(value, int):
|
|
249
|
+
return StaticValue(value)
|
|
250
|
+
elif isinstance(value, bool):
|
|
251
|
+
return StaticValue(value)
|
|
252
|
+
elif isinstance(value, str):
|
|
253
|
+
return StaticValue(value)
|
|
254
|
+
else:
|
|
255
|
+
return None
|
|
256
|
+
except (json.JSONDecodeError, ValueError):
|
|
257
|
+
# Fallback to string
|
|
258
|
+
return StaticValue(s)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def get_attribute_setter_info(
|
|
262
|
+
conn: sqlite3.Connection,
|
|
263
|
+
component_type: str,
|
|
264
|
+
attribute_name: str,
|
|
265
|
+
) -> Dict[str, Any]:
|
|
266
|
+
"""
|
|
267
|
+
Get the appropriate function name for setting an attribute.
|
|
268
|
+
|
|
269
|
+
Args:
|
|
270
|
+
conn: Database connection
|
|
271
|
+
component_type: Type of component
|
|
272
|
+
attribute_name: Name of the attribute
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
Dictionary with setter function information
|
|
276
|
+
|
|
277
|
+
Raises:
|
|
278
|
+
ValidationError: If attribute or data type is unknown
|
|
279
|
+
"""
|
|
280
|
+
rule = get_validation_rule(conn, component_type, attribute_name)
|
|
281
|
+
|
|
282
|
+
function_name = {
|
|
283
|
+
"float": "set_float_attribute",
|
|
284
|
+
"int": "set_integer_attribute",
|
|
285
|
+
"boolean": "set_boolean_attribute",
|
|
286
|
+
"string": "set_string_attribute",
|
|
287
|
+
}.get(rule.data_type)
|
|
288
|
+
|
|
289
|
+
if not function_name:
|
|
290
|
+
raise ValidationError(f"Unknown data type: {rule.data_type}")
|
|
291
|
+
|
|
292
|
+
return {
|
|
293
|
+
"function_name": function_name,
|
|
294
|
+
"data_type": rule.data_type,
|
|
295
|
+
"allows_static": rule.allows_static,
|
|
296
|
+
"allows_timeseries": rule.allows_timeseries,
|
|
297
|
+
"is_required": rule.is_required,
|
|
298
|
+
"default_value": rule.default_value_string,
|
|
299
|
+
"unit": rule.unit,
|
|
300
|
+
"description": rule.description
|
|
301
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pyconvexity
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python library for energy system modeling and optimization with PyPSA
|
|
5
|
+
Author-email: Convexity Team <info@convexity.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/bayesian-energy/convexity-js
|
|
8
|
+
Project-URL: Repository, https://github.com/bayesian-energy/convexity-js
|
|
9
|
+
Project-URL: Issues, https://github.com/bayesian-energy/convexity-js/issues
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering
|
|
19
|
+
Requires-Python: >=3.9
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
Requires-Dist: pandas>=1.5.0
|
|
22
|
+
Requires-Dist: numpy>=1.21.0
|
|
23
|
+
Requires-Dist: pyarrow>=10.0.0
|
|
24
|
+
Provides-Extra: pypsa
|
|
25
|
+
Requires-Dist: pypsa>=0.25.0; extra == "pypsa"
|
|
26
|
+
Requires-Dist: networkx; extra == "pypsa"
|
|
27
|
+
Requires-Dist: scipy; extra == "pypsa"
|
|
28
|
+
Requires-Dist: xarray; extra == "pypsa"
|
|
29
|
+
Provides-Extra: excel
|
|
30
|
+
Requires-Dist: openpyxl>=3.0.0; extra == "excel"
|
|
31
|
+
Requires-Dist: xlsxwriter>=3.0.0; extra == "excel"
|
|
32
|
+
Provides-Extra: netcdf
|
|
33
|
+
Requires-Dist: netcdf4>=1.6.0; extra == "netcdf"
|
|
34
|
+
Requires-Dist: xarray>=2022.3.0; extra == "netcdf"
|
|
35
|
+
Provides-Extra: dev
|
|
36
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
37
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
38
|
+
Requires-Dist: black>=22.0.0; extra == "dev"
|
|
39
|
+
Requires-Dist: isort>=5.10.0; extra == "dev"
|
|
40
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
41
|
+
Requires-Dist: pre-commit>=2.20.0; extra == "dev"
|
|
42
|
+
Provides-Extra: all
|
|
43
|
+
Requires-Dist: pyconvexity[excel,netcdf,pypsa]; extra == "all"
|
|
44
|
+
|
|
45
|
+
# PyConvexity
|
|
46
|
+
|
|
47
|
+
**Energy system modeling library for optimization and analysis.**
|
|
48
|
+
|
|
49
|
+
PyConvexity provides the core functionality of the [Convexity](https://github.com/bayesian-energy/convexity-js) desktop application as a reusable, pip-installable Python library.
|
|
50
|
+
|
|
51
|
+
## Installation
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install pyconvexity
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Quick Start
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
import pyconvexity as px
|
|
61
|
+
|
|
62
|
+
# Create a new energy system model database
|
|
63
|
+
px.create_database_with_schema("my_model.db")
|
|
64
|
+
|
|
65
|
+
# Create a network
|
|
66
|
+
with px.database_context("my_model.db") as conn:
|
|
67
|
+
network_req = px.CreateNetworkRequest(
|
|
68
|
+
name="My Energy Network",
|
|
69
|
+
description="Example renewable energy system",
|
|
70
|
+
start_time="2024-01-01 00:00:00",
|
|
71
|
+
end_time="2024-01-02 00:00:00",
|
|
72
|
+
time_resolution="H"
|
|
73
|
+
)
|
|
74
|
+
network_id = px.create_network(conn, network_req)
|
|
75
|
+
|
|
76
|
+
# Create carriers (energy types)
|
|
77
|
+
ac_carrier = px.create_carrier(conn, network_id, "AC")
|
|
78
|
+
|
|
79
|
+
# Create components
|
|
80
|
+
bus_id = px.create_component(
|
|
81
|
+
conn, network_id, "BUS", "Main Bus",
|
|
82
|
+
latitude=40.7128, longitude=-74.0060,
|
|
83
|
+
carrier_id=ac_carrier
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# Set component attributes
|
|
87
|
+
px.set_static_attribute(conn, bus_id, "v_nom", px.StaticValue(230.0))
|
|
88
|
+
|
|
89
|
+
conn.commit()
|
|
90
|
+
|
|
91
|
+
print(f"✅ Created network {network_id} with bus {bus_id}")
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Features
|
|
95
|
+
|
|
96
|
+
- **Database Management**: SQLite-based energy system model storage
|
|
97
|
+
- **Component Modeling**: Buses, generators, loads, lines, storage, etc.
|
|
98
|
+
- **Time Series Support**: Efficient storage and retrieval of temporal data
|
|
99
|
+
- **Validation**: Built-in validation rules for energy system components
|
|
100
|
+
- **PyPSA Integration**: Compatible with PyPSA energy system modeling
|
|
101
|
+
- **Type Safety**: Full type hints and data validation
|
|
102
|
+
|
|
103
|
+
## Core Concepts
|
|
104
|
+
|
|
105
|
+
### Networks
|
|
106
|
+
Energy system models organized as networks with time periods and carriers.
|
|
107
|
+
|
|
108
|
+
### Components
|
|
109
|
+
Physical and virtual elements: buses, generators, loads, transmission lines, storage units, etc.
|
|
110
|
+
|
|
111
|
+
### Attributes
|
|
112
|
+
Component properties that can be static values or time series data.
|
|
113
|
+
|
|
114
|
+
### Scenarios
|
|
115
|
+
Different parameter sets for the same network topology.
|
|
116
|
+
|
|
117
|
+
## Documentation
|
|
118
|
+
|
|
119
|
+
- **Full Documentation**: [Convexity Documentation](https://github.com/bayesian-energy/convexity-js)
|
|
120
|
+
- **API Reference**: See docstrings in the code
|
|
121
|
+
- **Examples**: Check the `examples/` directory
|
|
122
|
+
|
|
123
|
+
## Development
|
|
124
|
+
|
|
125
|
+
PyConvexity is developed as part of the [Convexity](https://github.com/bayesian-energy/convexity-js) project by [Bayesian Energy](https://bayesianenergy.com).
|
|
126
|
+
|
|
127
|
+
## License
|
|
128
|
+
|
|
129
|
+
MIT License - see [LICENSE](https://github.com/bayesian-energy/convexity-js/blob/main/LICENSE) file for details.
|
|
130
|
+
|
|
131
|
+
## Related Projects
|
|
132
|
+
|
|
133
|
+
- **[Convexity](https://github.com/bayesian-energy/convexity-js)**: Desktop application for energy system modeling
|
|
134
|
+
- **[PyPSA](https://pypsa.org/)**: Python for Power System Analysis
|
|
135
|
+
- **[Linopy](https://linopy.readthedocs.io/)**: Linear optimization with Python
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
pyconvexity/__init__.py,sha256=mEtafBwQ1A9s-hEv3o3XeXlJ7iFtbdS691wVUUw5miY,3303
|
|
2
|
+
pyconvexity/_version.py,sha256=5CA6z91JO_fS9ADhN6383Ps_rUNBx3K4gJNbVRJmeYY,133
|
|
3
|
+
pyconvexity/core/__init__.py,sha256=4SYAE4zqzGIRFSP4IoT7EzK-LCTB1HLe9EWhfi2aUmU,1253
|
|
4
|
+
pyconvexity/core/database.py,sha256=zqurVzPGuWei0jII1PTMAY-qaR-fr_A7uLxm__6KIlE,9276
|
|
5
|
+
pyconvexity/core/errors.py,sha256=HhrrOOEBJrzyB56_pmqh3NWvX6uHqWWNkdE5XM16rYI,2881
|
|
6
|
+
pyconvexity/core/types.py,sha256=eoVOAcDJWzjJKO9lYN7O17Us0XbahBpVBwv6uxdldh0,8508
|
|
7
|
+
pyconvexity/models/__init__.py,sha256=eVwf0ZTTEq1nM9M3NSMvj2yLPUOPNKMXv2A5GLT34-c,1470
|
|
8
|
+
pyconvexity/models/attributes.py,sha256=I6t1x7HX1gLw_lA6K87_GGmLAO34fpe4ZDX7_3LzMx4,13974
|
|
9
|
+
pyconvexity/models/components.py,sha256=K7QWelMVU_D18skvBZbap9dxP2AMS2116fcpmemkE6U,14629
|
|
10
|
+
pyconvexity/models/network.py,sha256=-itmot8StUdXogDpZUhGVIUC5uAEucYQ1LiTN1vPdA4,12923
|
|
11
|
+
pyconvexity/validation/__init__.py,sha256=_6SVqXkaDFqmagub_O064Zm_QIdBrOra-Gvvbo9vM4I,549
|
|
12
|
+
pyconvexity/validation/rules.py,sha256=bshO2Ibw8tBurg708Dmf79rIBoGV32t-jNHltjap9Pw,9323
|
|
13
|
+
pyconvexity-0.1.0.dist-info/METADATA,sha256=ltUWa115nNRTIAl4xbzFDjC2s9Q5LOhJcJHwMBS6ea4,4751
|
|
14
|
+
pyconvexity-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
15
|
+
pyconvexity-0.1.0.dist-info/top_level.txt,sha256=wFPEDXVaebR3JO5Tt3HNse-ws5aROCcxEco15d6j64s,12
|
|
16
|
+
pyconvexity-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pyconvexity
|