intersect-sdk 0.6.1a1__tar.gz → 0.6.2__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.
- intersect_sdk-0.6.2/LICENSE +29 -0
- intersect_sdk-0.6.2/PKG-INFO +60 -0
- intersect_sdk-0.6.2/README.md +33 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/pyproject.toml +12 -6
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/__init__.py +2 -1
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/event_metadata.py +10 -2
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/messages/event.py +2 -2
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/messages/lifecycle.py +2 -2
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/messages/userspace.py +2 -2
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/schema.py +2 -2
- intersect_sdk-0.6.2/src/intersect_sdk/_internal/version.py +18 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/version_resolver.py +2 -2
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/service.py +2 -2
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/version.py +9 -3
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/tests/fixtures/example_schema.json +1 -1
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/tests/unit/test_lifecycle_message.py +2 -2
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/tests/unit/test_schema_invalids.py +5 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/tests/unit/test_userspace_message.py +2 -2
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/tests/unit/test_version_resolver.py +2 -2
- intersect_sdk-0.6.1a1/PKG-INFO +0 -39
- intersect_sdk-0.6.1a1/README.md +0 -16
- intersect_sdk-0.6.1a1/src/intersect_sdk/_internal/compression.py.tmp +0 -38
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/__init__.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/constants.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/control_plane/__init__.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/control_plane/brokers/__init__.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/control_plane/brokers/amqp_client.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/control_plane/brokers/broker_client.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/control_plane/brokers/mqtt_client.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/control_plane/control_plane_manager.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/control_plane/discovery_service.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/data_plane/__init__.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/data_plane/data_plane_manager.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/data_plane/minio_utils.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/exceptions.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/function_metadata.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/interfaces.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/logger.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/messages/__init__.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/pydantic_schema_generator.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/stoppable_thread.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/utils.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/app_lifecycle.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/capability/__init__.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/capability/base.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/client.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/client_callback_definitions.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/config/__init__.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/config/client.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/config/service.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/config/shared.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/constants.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/core_definitions.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/py.typed +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/schema.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/service_definitions.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/tests/__init__.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/tests/conftest.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/tests/e2e/__init__.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/tests/e2e/test_examples.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/tests/fixtures/__init__.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/tests/fixtures/example_schema.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/tests/fixtures/return_type_mismatch.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/tests/integration/__init__.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/tests/integration/test_return_type_mismatch.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/tests/integration/test_service.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/tests/unit/__init__.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/tests/unit/test_annotations.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/tests/unit/test_base_capability_implementation.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/tests/unit/test_config.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/tests/unit/test_invalid_schema_runtime.py +0 -0
- {intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/tests/unit/test_schema_valid.py +0 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024, INTERSECT-SDK
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
and/or other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
17
|
+
contributors may be used to endorse or promote products derived from
|
|
18
|
+
this software without specific prior written permission.
|
|
19
|
+
|
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
21
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
22
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
24
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
25
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
26
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
27
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
28
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
29
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: intersect-sdk
|
|
3
|
+
Version: 0.6.2
|
|
4
|
+
Summary: Python SDK to interact with INTERSECT
|
|
5
|
+
Keywords: intersect
|
|
6
|
+
Author-Email: Lance Drane <dranelt@ornl.gov>, Marshall McDonnell <mcdonnellmt@ornl.gov>, Seth Hitefield <hitefieldsd@ornl.gov>, Andrew Ayres <ayresaf@ornl.gov>, Gregory Cage <cagege@ornl.gov>, Jesse McGaha <mcgahajr@ornl.gov>, Robert Smith <smithrw@ornl.gov>, Gavin Wiggins <wigginsg@ornl.gov>, Michael Brim <brimmj@ornl.gov>, Rick Archibald <archibaldrk@ornl.gov>, Addi Malviya Thakur <malviyaa@ornl.gov>
|
|
7
|
+
License: BSD-3-Clause
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Requires-Python: <4.0,>=3.8.10
|
|
14
|
+
Requires-Dist: pydantic>=2.7.0
|
|
15
|
+
Requires-Dist: retrying<2.0.0,>=1.3.4
|
|
16
|
+
Requires-Dist: paho-mqtt<2.0.0,>=1.6.1
|
|
17
|
+
Requires-Dist: minio>=7.2.3
|
|
18
|
+
Requires-Dist: jsonschema[format-nongpl]>=4.21.1
|
|
19
|
+
Requires-Dist: pika<2.0.0,>=1.3.2; extra == "amqp"
|
|
20
|
+
Requires-Dist: eval-type-backport>=0.1.3; extra == "py38"
|
|
21
|
+
Requires-Dist: sphinx>=5.3.0; extra == "docs"
|
|
22
|
+
Requires-Dist: furo>=2023.3.27; extra == "docs"
|
|
23
|
+
Provides-Extra: amqp
|
|
24
|
+
Provides-Extra: py38
|
|
25
|
+
Provides-Extra: docs
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# INTERSECT-SDK
|
|
29
|
+
|
|
30
|
+
The INTERSECT-SDK is a framework for microservices to integrate themselves into the wider Interconnected Science Ecosystem (INTERSECT).
|
|
31
|
+
|
|
32
|
+
Please note that this README is currently a work in progress.
|
|
33
|
+
|
|
34
|
+
## What is INTERSECT?
|
|
35
|
+
[INTERSECT](https://www.ornl.gov/intersect) was designed as a specific usecase - as an open federated hardware/software architecture for the laboratory of the future, which connects scientific instruments, robot-controlled laboratories and edge/center computing/data resources to enable autonomous experiments, self-driving laboratories, smart manufacturing, and AI-driven design, discovery and evaluation.
|
|
36
|
+
|
|
37
|
+
## What are the core design philosophies of the SDK?
|
|
38
|
+
|
|
39
|
+
- Event-driven architecture
|
|
40
|
+
- Support core interaction types: request/response, events, commands, statuses
|
|
41
|
+
- Borrows several concepts from [AsyncAPI](https://www.asyncapi.com/docs/reference/specification/latest), and intends to support multiple different protocols. Currently, we support MQTT 3.1.1 and AMQP 0.9.1, but other protocols will be supported as well.
|
|
42
|
+
- Users automatically generate schema from code; schemas are part of the core contract of an INTERSECT microservice, and both external inputs and microservice outputs are required to uphold this contract.
|
|
43
|
+
|
|
44
|
+
## Authors
|
|
45
|
+
|
|
46
|
+
INTERSECT SDK was created by its [contributors](https://github.com/intersect-sdk/python-sdk/graphs/contributors).
|
|
47
|
+
|
|
48
|
+
### Citing INTERSECT-SDK
|
|
49
|
+
|
|
50
|
+
If you are referencing INTERSECT-SDK in a publication, please cite the following paper:
|
|
51
|
+
|
|
52
|
+
* Addi Malviya Thakur, Seth Hitefield, Marshall McDonnell, Matthew Wolf, Richard Archibald, Lance Drane, Kevin Roccapriore, Maxim Ziatdinov, Jesse McGaha, Robert Smith, John Hetrick, Mark Abraham, Sergey Yakubov, Greg Watson, Ben Chance, Clara Nguyen, Matthew Baker, Robert Michael, Elke Arenholz & Ben Mintz. Towards a Software Development Framework for Interconnected Science Ecosystems. In: Doug, K., Al, G., Pophale, S., Liu, H., Parete-Koon, S. (eds) Accelerating Science and Engineering Discoveries Through Integrated Research Infrastructure for Experiment, Big Data, Modeling and Simulation. SMC 2022. Communications in Computer and Information Science, vol 1690. Springer, Cham. https://doi.org/10.1007/978-3-031-23606-8_13
|
|
53
|
+
|
|
54
|
+
On GitHub, you can copy this citation in APA or BibTeX format via the "Cite this repository" button. Or, see the comments in `CITATION.cff` for the raw BibTeX.
|
|
55
|
+
|
|
56
|
+
## Acknowledgements
|
|
57
|
+
|
|
58
|
+
The INTERSECT-SDK development has received funding support / sponsorship from the following:
|
|
59
|
+
|
|
60
|
+
* Laboratory Directed Research and Development Program of Oak Ridge National Laboratory, managed by UT-Battelle, LLC, for the U. S. Department of Energy.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# INTERSECT-SDK
|
|
2
|
+
|
|
3
|
+
The INTERSECT-SDK is a framework for microservices to integrate themselves into the wider Interconnected Science Ecosystem (INTERSECT).
|
|
4
|
+
|
|
5
|
+
Please note that this README is currently a work in progress.
|
|
6
|
+
|
|
7
|
+
## What is INTERSECT?
|
|
8
|
+
[INTERSECT](https://www.ornl.gov/intersect) was designed as a specific usecase - as an open federated hardware/software architecture for the laboratory of the future, which connects scientific instruments, robot-controlled laboratories and edge/center computing/data resources to enable autonomous experiments, self-driving laboratories, smart manufacturing, and AI-driven design, discovery and evaluation.
|
|
9
|
+
|
|
10
|
+
## What are the core design philosophies of the SDK?
|
|
11
|
+
|
|
12
|
+
- Event-driven architecture
|
|
13
|
+
- Support core interaction types: request/response, events, commands, statuses
|
|
14
|
+
- Borrows several concepts from [AsyncAPI](https://www.asyncapi.com/docs/reference/specification/latest), and intends to support multiple different protocols. Currently, we support MQTT 3.1.1 and AMQP 0.9.1, but other protocols will be supported as well.
|
|
15
|
+
- Users automatically generate schema from code; schemas are part of the core contract of an INTERSECT microservice, and both external inputs and microservice outputs are required to uphold this contract.
|
|
16
|
+
|
|
17
|
+
## Authors
|
|
18
|
+
|
|
19
|
+
INTERSECT SDK was created by its [contributors](https://github.com/intersect-sdk/python-sdk/graphs/contributors).
|
|
20
|
+
|
|
21
|
+
### Citing INTERSECT-SDK
|
|
22
|
+
|
|
23
|
+
If you are referencing INTERSECT-SDK in a publication, please cite the following paper:
|
|
24
|
+
|
|
25
|
+
* Addi Malviya Thakur, Seth Hitefield, Marshall McDonnell, Matthew Wolf, Richard Archibald, Lance Drane, Kevin Roccapriore, Maxim Ziatdinov, Jesse McGaha, Robert Smith, John Hetrick, Mark Abraham, Sergey Yakubov, Greg Watson, Ben Chance, Clara Nguyen, Matthew Baker, Robert Michael, Elke Arenholz & Ben Mintz. Towards a Software Development Framework for Interconnected Science Ecosystems. In: Doug, K., Al, G., Pophale, S., Liu, H., Parete-Koon, S. (eds) Accelerating Science and Engineering Discoveries Through Integrated Research Infrastructure for Experiment, Big Data, Modeling and Simulation. SMC 2022. Communications in Computer and Information Science, vol 1690. Springer, Cham. https://doi.org/10.1007/978-3-031-23606-8_13
|
|
26
|
+
|
|
27
|
+
On GitHub, you can copy this citation in APA or BibTeX format via the "Cite this repository" button. Or, see the comments in `CITATION.cff` for the raw BibTeX.
|
|
28
|
+
|
|
29
|
+
## Acknowledgements
|
|
30
|
+
|
|
31
|
+
The INTERSECT-SDK development has received funding support / sponsorship from the following:
|
|
32
|
+
|
|
33
|
+
* Laboratory Directed Research and Development Program of Oak Ridge National Laboratory, managed by UT-Battelle, LLC, for the U. S. Department of Energy.
|
|
@@ -10,13 +10,16 @@ authors = [
|
|
|
10
10
|
{ name = "Jesse McGaha", email = "mcgahajr@ornl.gov" },
|
|
11
11
|
{ name = "Robert Smith", email = "smithrw@ornl.gov" },
|
|
12
12
|
{ name = "Gavin Wiggins", email = "wigginsg@ornl.gov" },
|
|
13
|
+
{ name = "Michael Brim", email = "brimmj@ornl.gov" },
|
|
14
|
+
{ name = "Rick Archibald", email = "archibaldrk@ornl.gov" },
|
|
15
|
+
{ name = "Addi Malviya Thakur", email = "malviyaa@ornl.gov" },
|
|
13
16
|
]
|
|
14
17
|
readme = "README.md"
|
|
15
18
|
requires-python = ">=3.8.10,<4.0"
|
|
16
19
|
keywords = [
|
|
17
20
|
"intersect",
|
|
18
21
|
]
|
|
19
|
-
|
|
22
|
+
dynamic = []
|
|
20
23
|
classifiers = [
|
|
21
24
|
"Programming Language :: Python :: 3",
|
|
22
25
|
"Programming Language :: Python :: 3.8",
|
|
@@ -31,6 +34,10 @@ dependencies = [
|
|
|
31
34
|
"minio>=7.2.3",
|
|
32
35
|
"jsonschema[format-nongpl]>=4.21.1",
|
|
33
36
|
]
|
|
37
|
+
version = "0.6.2"
|
|
38
|
+
|
|
39
|
+
[project.license]
|
|
40
|
+
text = "BSD-3-Clause"
|
|
34
41
|
|
|
35
42
|
[project.optional-dependencies]
|
|
36
43
|
amqp = [
|
|
@@ -39,6 +46,10 @@ amqp = [
|
|
|
39
46
|
py38 = [
|
|
40
47
|
"eval-type-backport>=0.1.3",
|
|
41
48
|
]
|
|
49
|
+
docs = [
|
|
50
|
+
"sphinx>=5.3.0",
|
|
51
|
+
"furo>=2023.3.27",
|
|
52
|
+
]
|
|
42
53
|
|
|
43
54
|
[tool.pdm.dev-dependencies]
|
|
44
55
|
lint = [
|
|
@@ -52,11 +63,6 @@ test = [
|
|
|
52
63
|
"pytest-cov>=4.1.0",
|
|
53
64
|
"httpretty>=1.1.4",
|
|
54
65
|
]
|
|
55
|
-
doc = [
|
|
56
|
-
"sphinx>=5.3.0",
|
|
57
|
-
"furo>=2023.3.27",
|
|
58
|
-
]
|
|
59
|
-
":lint" = []
|
|
60
66
|
|
|
61
67
|
[tool.pdm.scripts]
|
|
62
68
|
test-all = "pytest tests/ --cov=src/intersect_sdk/ --cov-fail-under=80 --cov-report=html:reports/htmlcov/ --cov-report=xml:reports/coverage_report.xml --junitxml=reports/junit.xml"
|
|
@@ -34,7 +34,7 @@ from .service_definitions import (
|
|
|
34
34
|
intersect_message,
|
|
35
35
|
intersect_status,
|
|
36
36
|
)
|
|
37
|
-
from .version import __version__, version_info
|
|
37
|
+
from .version import __version__, version_info, version_string
|
|
38
38
|
|
|
39
39
|
__all__ = [
|
|
40
40
|
'IntersectDataHandler',
|
|
@@ -61,4 +61,5 @@ __all__ = [
|
|
|
61
61
|
'DataStoreConfigMap',
|
|
62
62
|
'__version__',
|
|
63
63
|
'version_info',
|
|
64
|
+
'version_string',
|
|
64
65
|
]
|
|
@@ -51,10 +51,18 @@ def definition_metadata_differences(
|
|
|
51
51
|
differences.append(('event_type', str(definition.event_type), str(metadata.type)))
|
|
52
52
|
if definition.content_type != metadata.content_type:
|
|
53
53
|
differences.append(
|
|
54
|
-
(
|
|
54
|
+
(
|
|
55
|
+
'content_type',
|
|
56
|
+
f'{definition.content_type.__class__.__name__}.{definition.content_type.name}',
|
|
57
|
+
f'{metadata.content_type.__class__.__name__}.{metadata.content_type.name}',
|
|
58
|
+
)
|
|
55
59
|
)
|
|
56
60
|
if definition.data_handler != metadata.data_transfer_handler:
|
|
57
61
|
differences.append(
|
|
58
|
-
(
|
|
62
|
+
(
|
|
63
|
+
'data_handler',
|
|
64
|
+
f'{definition.data_handler.__class__.__name__}.{definition.data_handler.name}',
|
|
65
|
+
f'{metadata.data_transfer_handler.__class__.__name__}.{metadata.data_transfer_handler.name}',
|
|
66
|
+
)
|
|
59
67
|
)
|
|
60
68
|
return differences
|
|
@@ -16,7 +16,7 @@ from typing_extensions import Annotated, TypedDict
|
|
|
16
16
|
|
|
17
17
|
from ...constants import SYSTEM_OF_SYSTEM_REGEX
|
|
18
18
|
from ...core_definitions import IntersectDataHandler, IntersectMimeType
|
|
19
|
-
from ...version import
|
|
19
|
+
from ...version import version_string
|
|
20
20
|
from ..data_plane.minio_utils import MinioPayload
|
|
21
21
|
|
|
22
22
|
# TODO - another property we should consider is an optional max_wait_time for events which are fired from functions.
|
|
@@ -139,7 +139,7 @@ def create_event_message(
|
|
|
139
139
|
headers=EventMessageHeaders(
|
|
140
140
|
source=source,
|
|
141
141
|
created_at=datetime.datetime.now(tz=datetime.timezone.utc),
|
|
142
|
-
sdk_version=
|
|
142
|
+
sdk_version=version_string,
|
|
143
143
|
event_name=event_name,
|
|
144
144
|
data_handler=data_handler,
|
|
145
145
|
),
|
{intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/messages/lifecycle.py
RENAMED
|
@@ -16,7 +16,7 @@ from pydantic import AwareDatetime, Field, TypeAdapter
|
|
|
16
16
|
from typing_extensions import Annotated, TypedDict
|
|
17
17
|
|
|
18
18
|
from ...constants import SYSTEM_OF_SYSTEM_REGEX
|
|
19
|
-
from ...version import
|
|
19
|
+
from ...version import version_string
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
class LifecycleType(IntEnum):
|
|
@@ -155,7 +155,7 @@ def create_lifecycle_message(
|
|
|
155
155
|
source=source,
|
|
156
156
|
destination=destination,
|
|
157
157
|
created_at=datetime.datetime.now(tz=datetime.timezone.utc),
|
|
158
|
-
sdk_version=
|
|
158
|
+
sdk_version=version_string,
|
|
159
159
|
lifecycle_type=lifecycle_type,
|
|
160
160
|
),
|
|
161
161
|
payload=payload,
|
{intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/messages/userspace.py
RENAMED
|
@@ -18,7 +18,7 @@ from typing_extensions import Annotated, TypedDict
|
|
|
18
18
|
|
|
19
19
|
from ...constants import SYSTEM_OF_SYSTEM_REGEX
|
|
20
20
|
from ...core_definitions import IntersectDataHandler, IntersectMimeType
|
|
21
|
-
from ...version import
|
|
21
|
+
from ...version import version_string
|
|
22
22
|
from ..data_plane.minio_utils import MinioPayload
|
|
23
23
|
|
|
24
24
|
|
|
@@ -152,7 +152,7 @@ def create_userspace_message(
|
|
|
152
152
|
headers=UserspaceMessageHeader(
|
|
153
153
|
source=source,
|
|
154
154
|
destination=destination,
|
|
155
|
-
sdk_version=
|
|
155
|
+
sdk_version=version_string,
|
|
156
156
|
created_at=datetime.datetime.now(tz=datetime.timezone.utc),
|
|
157
157
|
data_handler=data_handler,
|
|
158
158
|
has_error=has_error,
|
|
@@ -16,7 +16,7 @@ from typing import (
|
|
|
16
16
|
from pydantic import PydanticUserError, TypeAdapter
|
|
17
17
|
from typing_extensions import TypeAliasType
|
|
18
18
|
|
|
19
|
-
from ..version import
|
|
19
|
+
from ..version import version_string
|
|
20
20
|
from .constants import (
|
|
21
21
|
BASE_EVENT_ATTR,
|
|
22
22
|
BASE_RESPONSE_ATTR,
|
|
@@ -513,7 +513,7 @@ def get_schema_and_functions_from_capability_implementation(
|
|
|
513
513
|
|
|
514
514
|
asyncapi_spec = {
|
|
515
515
|
'asyncapi': ASYNCAPI_VERSION,
|
|
516
|
-
'x-intersect-version':
|
|
516
|
+
'x-intersect-version': version_string,
|
|
517
517
|
'info': {
|
|
518
518
|
'title': capability_name.hierarchy_string('.'),
|
|
519
519
|
'version': '0.0.0', # NOTE: this will be modified by INTERSECT CORE, users do not manage their schema versions
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Version sanity checks to make sure that the release version is properly formatted."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def strip_version_metadata(version: str) -> str:
|
|
5
|
+
"""Given a string, do the following.
|
|
6
|
+
|
|
7
|
+
1) Strip out pre-release/build-metadata from the string
|
|
8
|
+
2) If the string is missing all of <MAJOR>.<MINOR>.<PATCH>, raise runtime error
|
|
9
|
+
|
|
10
|
+
This is necessary because INTERSECT works off of a strict SemVer string and does not understand build metadata.
|
|
11
|
+
"""
|
|
12
|
+
import re
|
|
13
|
+
|
|
14
|
+
sem_ver = re.search(r'\d+\.\d+\.\d+', version)
|
|
15
|
+
if sem_ver is None:
|
|
16
|
+
msg = 'Package version does not contain a semantic version "<MAJOR>.<MINOR>.<DEBUG>", please fix this'
|
|
17
|
+
raise RuntimeError(msg)
|
|
18
|
+
return sem_ver.group()
|
{intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/version_resolver.py
RENAMED
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
from ..core_definitions import IntersectDataHandler
|
|
6
|
-
from ..version import
|
|
6
|
+
from ..version import version_info, version_string
|
|
7
7
|
from .logger import logger
|
|
8
8
|
|
|
9
9
|
if TYPE_CHECKING:
|
|
@@ -53,6 +53,6 @@ def resolve_user_version(msg: UserspaceMessage | EventMessage) -> bool:
|
|
|
53
53
|
"""
|
|
54
54
|
return _resolve_user_version(
|
|
55
55
|
msg=msg,
|
|
56
|
-
our_version=
|
|
56
|
+
our_version=version_string,
|
|
57
57
|
our_version_info=version_info,
|
|
58
58
|
)
|
|
@@ -49,7 +49,7 @@ from ._internal.version_resolver import resolve_user_version
|
|
|
49
49
|
from .capability.base import IntersectBaseCapabilityImplementation
|
|
50
50
|
from .config.service import IntersectServiceConfig
|
|
51
51
|
from .core_definitions import IntersectDataHandler, IntersectMimeType
|
|
52
|
-
from .version import
|
|
52
|
+
from .version import version_string
|
|
53
53
|
|
|
54
54
|
if TYPE_CHECKING:
|
|
55
55
|
from ._internal.function_metadata import FunctionMetadata
|
|
@@ -361,7 +361,7 @@ class IntersectService(IntersectEventObserver):
|
|
|
361
361
|
return None
|
|
362
362
|
if not resolve_user_version(message):
|
|
363
363
|
return self._make_error_message(
|
|
364
|
-
f'SDK version incompatibility. Service version: {
|
|
364
|
+
f'SDK version incompatibility. Service version: {version_string} . Sender version: {message["headers"]["sdk_version"]}',
|
|
365
365
|
message,
|
|
366
366
|
)
|
|
367
367
|
|
|
@@ -5,11 +5,17 @@ These values are often used programmatically by the SDK, but can be used by appl
|
|
|
5
5
|
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
from ._internal.version import strip_version_metadata
|
|
9
|
+
|
|
10
|
+
# may include build metadata
|
|
11
|
+
__version__ = '0.6.2'
|
|
12
|
+
|
|
13
|
+
version_string = strip_version_metadata(__version__)
|
|
9
14
|
"""
|
|
10
|
-
Version string in the format <MAJOR>.<MINOR>.<DEBUG> . Follows semantic versioning rules.
|
|
15
|
+
Version string in the format <MAJOR>.<MINOR>.<DEBUG> . Follows semantic versioning rules, strips out additional build metadata.
|
|
11
16
|
"""
|
|
12
|
-
|
|
17
|
+
|
|
18
|
+
version_info: tuple[int, int, int] = tuple([int(x) for x in version_string.split('.')]) # type: ignore[assignment]
|
|
13
19
|
"""
|
|
14
20
|
Integer tuple in the format <MAJOR>,<MINOR>,<DEBUG> . Follows semantic versioning rules.
|
|
15
21
|
"""
|
|
@@ -6,7 +6,7 @@ import datetime
|
|
|
6
6
|
import uuid
|
|
7
7
|
|
|
8
8
|
import pytest
|
|
9
|
-
from intersect_sdk import
|
|
9
|
+
from intersect_sdk import version_string
|
|
10
10
|
from intersect_sdk._internal.messages.lifecycle import (
|
|
11
11
|
LifecycleType,
|
|
12
12
|
create_lifecycle_message,
|
|
@@ -95,6 +95,6 @@ def test_create_lifecycle_message():
|
|
|
95
95
|
# enforce UTC
|
|
96
96
|
assert msg['headers']['created_at'].tzinfo == datetime.timezone.utc
|
|
97
97
|
assert msg['headers']['lifecycle_type'] == LifecycleType.SHUTDOWN
|
|
98
|
-
assert msg['headers']['sdk_version'] ==
|
|
98
|
+
assert msg['headers']['sdk_version'] == version_string
|
|
99
99
|
assert msg['headers']['source'] == 'source'
|
|
100
100
|
assert msg['headers']['destination'] == 'destination'
|
|
@@ -14,6 +14,7 @@ General rules of "invalids":
|
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
16
|
import datetime
|
|
17
|
+
import sys
|
|
17
18
|
from collections import namedtuple
|
|
18
19
|
from dataclasses import dataclass
|
|
19
20
|
from typing import Any, Dict, FrozenSet, Generator, List, NamedTuple, Set, Tuple, TypeVar
|
|
@@ -726,6 +727,10 @@ def test_default_not_serializable(caplog: pytest.LogCaptureFixture):
|
|
|
726
727
|
assert 'is not JSON serializable' in caplog.text
|
|
727
728
|
|
|
728
729
|
|
|
730
|
+
@pytest.mark.skipif(
|
|
731
|
+
sys.version_info >= (3, 11),
|
|
732
|
+
reason='Python 3.11 does not allow dataclasses to be constructed in this improper format',
|
|
733
|
+
)
|
|
729
734
|
def test_invalid_nested_defaults(caplog: pytest.LogCaptureFixture):
|
|
730
735
|
# should fail because we cannot serialize the defaults
|
|
731
736
|
class InvalidNestedDefaults(IntersectBaseCapabilityImplementation):
|
|
@@ -6,7 +6,7 @@ import datetime
|
|
|
6
6
|
import uuid
|
|
7
7
|
|
|
8
8
|
import pytest
|
|
9
|
-
from intersect_sdk import IntersectDataHandler, IntersectMimeType,
|
|
9
|
+
from intersect_sdk import IntersectDataHandler, IntersectMimeType, version_string
|
|
10
10
|
from intersect_sdk._internal.messages.userspace import (
|
|
11
11
|
create_userspace_message,
|
|
12
12
|
deserialize_and_validate_userspace_message,
|
|
@@ -100,6 +100,6 @@ def test_create_userspace_message():
|
|
|
100
100
|
# enforce UTC
|
|
101
101
|
assert msg['headers']['created_at'].tzinfo == datetime.timezone.utc
|
|
102
102
|
assert msg['headers']['data_handler'] == IntersectDataHandler.MESSAGE
|
|
103
|
-
assert msg['headers']['sdk_version'] ==
|
|
103
|
+
assert msg['headers']['sdk_version'] == version_string
|
|
104
104
|
assert msg['headers']['source'] == 'source'
|
|
105
105
|
assert msg['headers']['destination'] == 'destination'
|
|
@@ -17,8 +17,8 @@ import pytest
|
|
|
17
17
|
from intersect_sdk import (
|
|
18
18
|
IntersectDataHandler,
|
|
19
19
|
IntersectMimeType,
|
|
20
|
-
__version__,
|
|
21
20
|
version_info,
|
|
21
|
+
version_string,
|
|
22
22
|
)
|
|
23
23
|
from intersect_sdk._internal.messages.userspace import UserspaceMessage, UserspaceMessageHeader
|
|
24
24
|
from intersect_sdk._internal.version_resolver import _resolve_user_version, resolve_user_version
|
|
@@ -59,7 +59,7 @@ def test_version_info():
|
|
|
59
59
|
|
|
60
60
|
|
|
61
61
|
def test_equal_version_ok():
|
|
62
|
-
assert resolve_user_version(message_generator(
|
|
62
|
+
assert resolve_user_version(message_generator(version_string)) is True
|
|
63
63
|
|
|
64
64
|
|
|
65
65
|
def test_bugfix_up_ok():
|
intersect_sdk-0.6.1a1/PKG-INFO
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: intersect-sdk
|
|
3
|
-
Version: 0.6.1a1
|
|
4
|
-
Summary: Python SDK to interact with INTERSECT
|
|
5
|
-
Keywords: intersect
|
|
6
|
-
Author-Email: Lance Drane <dranelt@ornl.gov>, Marshall McDonnell <mcdonnellmt@ornl.gov>, Seth Hitefield <hitefieldsd@ornl.gov>, Andrew Ayres <ayresaf@ornl.gov>, Gregory Cage <cagege@ornl.gov>, Jesse McGaha <mcgahajr@ornl.gov>, Robert Smith <smithrw@ornl.gov>, Gavin Wiggins <wigginsg@ornl.gov>
|
|
7
|
-
Classifier: Programming Language :: Python :: 3
|
|
8
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
9
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
10
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
-
Requires-Python: <4.0,>=3.8.10
|
|
13
|
-
Requires-Dist: pydantic>=2.7.0
|
|
14
|
-
Requires-Dist: retrying<2.0.0,>=1.3.4
|
|
15
|
-
Requires-Dist: paho-mqtt<2.0.0,>=1.6.1
|
|
16
|
-
Requires-Dist: minio>=7.2.3
|
|
17
|
-
Requires-Dist: jsonschema[format-nongpl]>=4.21.1
|
|
18
|
-
Requires-Dist: pika<2.0.0,>=1.3.2; extra == "amqp"
|
|
19
|
-
Requires-Dist: eval-type-backport>=0.1.3; extra == "py38"
|
|
20
|
-
Provides-Extra: amqp
|
|
21
|
-
Provides-Extra: py38
|
|
22
|
-
Description-Content-Type: text/markdown
|
|
23
|
-
|
|
24
|
-
# INTERSECT-SDK
|
|
25
|
-
|
|
26
|
-
The INTERSECT-SDK is a framework for microservices to integrate themselves into the wider INTERSECT ecosystem.
|
|
27
|
-
|
|
28
|
-
Please note that this README is currently a work in progress.
|
|
29
|
-
|
|
30
|
-
## What is INTERSECT?
|
|
31
|
-
|
|
32
|
-
INTERSECT was designed as a specific usecase - as an open federated hardware/software architecture for the laboratory of the future, which connects scientific instruments, robot-controlled laboratories and edge/center computing/data resources to enable autonomous experiments, self-driving laboratories, smart manufacturing, and AI-driven design, discovery and evaluation.
|
|
33
|
-
|
|
34
|
-
## What are the core design philosophies of the SDK?
|
|
35
|
-
|
|
36
|
-
- Event-driven architecture
|
|
37
|
-
- Support core interaction types: request/response, events, commands, statuses
|
|
38
|
-
- Borrows several concepts from [AsyncAPI](https://www.asyncapi.com/docs/reference/specification/latest), and intends to support multiple different protocols. Currently, we support MQTT 3.1.1 and AMQP 0.9.1, but other protocols will be supported as well.
|
|
39
|
-
- Users automatically generate schema from code; schemas are part of the core contract of an INTERSECT microservice, and both external inputs and microservice outputs are required to uphold this contract.
|
intersect_sdk-0.6.1a1/README.md
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# INTERSECT-SDK
|
|
2
|
-
|
|
3
|
-
The INTERSECT-SDK is a framework for microservices to integrate themselves into the wider INTERSECT ecosystem.
|
|
4
|
-
|
|
5
|
-
Please note that this README is currently a work in progress.
|
|
6
|
-
|
|
7
|
-
## What is INTERSECT?
|
|
8
|
-
|
|
9
|
-
INTERSECT was designed as a specific usecase - as an open federated hardware/software architecture for the laboratory of the future, which connects scientific instruments, robot-controlled laboratories and edge/center computing/data resources to enable autonomous experiments, self-driving laboratories, smart manufacturing, and AI-driven design, discovery and evaluation.
|
|
10
|
-
|
|
11
|
-
## What are the core design philosophies of the SDK?
|
|
12
|
-
|
|
13
|
-
- Event-driven architecture
|
|
14
|
-
- Support core interaction types: request/response, events, commands, statuses
|
|
15
|
-
- Borrows several concepts from [AsyncAPI](https://www.asyncapi.com/docs/reference/specification/latest), and intends to support multiple different protocols. Currently, we support MQTT 3.1.1 and AMQP 0.9.1, but other protocols will be supported as well.
|
|
16
|
-
- Users automatically generate schema from code; schemas are part of the core contract of an INTERSECT microservice, and both external inputs and microservice outputs are required to uphold this contract.
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
"""Compression logic used inside INTERSECT.
|
|
2
|
-
|
|
3
|
-
Our current compression algorithm is Brotli - see https://stackoverflow.com/a/59255343 for a fairly comprehensive overview of serialization formats compatible with generic JSON.
|
|
4
|
-
Zstd is worth considering for instances where data isn't being persisted for long, as it is generally faster than Brotli (especially for decompression) - however, Zstd requires multithreading to maximize its potential.
|
|
5
|
-
|
|
6
|
-
Currently, we will ALWAYS compress the following:
|
|
7
|
-
- The schemas sent as part of the lifecycle message
|
|
8
|
-
- The PAYLOADS of UserspaceMessages *if the data itself is being sent in UserspaceMessages*
|
|
9
|
-
|
|
10
|
-
We do NOT want to compress message headers, though.
|
|
11
|
-
|
|
12
|
-
MINIO should always handle compression itself, see https://min.io/docs/minio/linux/administration/object-management/data-compression.html for details.
|
|
13
|
-
|
|
14
|
-
TODO - how should the data API handle compression?
|
|
15
|
-
|
|
16
|
-
TODO - We should consider NOT compressing audio, video, image, or any data which is already compressed.
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
import brotli
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def intersect_compress(message: bytes) -> bytes:
|
|
23
|
-
"""Compress MESSAGE using the compression algorithm, and return compression result.
|
|
24
|
-
|
|
25
|
-
Current compression algorithm is Brotli with the highest level quality.
|
|
26
|
-
"""
|
|
27
|
-
return brotli.compress(message, quality=11) # type: ignore[no-any-return]
|
|
28
|
-
|
|
29
|
-
def intersect_decompress(compressed: bytes) -> bytes:
|
|
30
|
-
"""Decompress COMPRESSED using the decompression algorithm, and return decompressed message.
|
|
31
|
-
|
|
32
|
-
Current decompression algorithm is Brotli.
|
|
33
|
-
"""
|
|
34
|
-
try:
|
|
35
|
-
return brotli.decompress(compressed) # type: ignore[no-any-return]
|
|
36
|
-
except brotli.error:
|
|
37
|
-
# if the parameters weren't compressed with Brotli, just return the input
|
|
38
|
-
return compressed
|
|
File without changes
|
|
File without changes
|
{intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/control_plane/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/data_plane/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/data_plane/minio_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
{intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/function_metadata.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/messages/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/_internal/stoppable_thread.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/src/intersect_sdk/client_callback_definitions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/tests/integration/test_return_type_mismatch.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{intersect_sdk-0.6.1a1 → intersect_sdk-0.6.2}/tests/unit/test_base_capability_implementation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|