mainsequence 2.0.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.
- mainsequence-2.0.0/LICENSE +40 -0
- mainsequence-2.0.0/PKG-INFO +105 -0
- mainsequence-2.0.0/README.md +1 -0
- mainsequence-2.0.0/mainsequence/__init__.py +0 -0
- mainsequence-2.0.0/mainsequence/__main__.py +9 -0
- mainsequence-2.0.0/mainsequence/cli/__init__.py +1 -0
- mainsequence-2.0.0/mainsequence/cli/api.py +157 -0
- mainsequence-2.0.0/mainsequence/cli/cli.py +442 -0
- mainsequence-2.0.0/mainsequence/cli/config.py +78 -0
- mainsequence-2.0.0/mainsequence/cli/ssh_utils.py +126 -0
- mainsequence-2.0.0/mainsequence/client/__init__.py +17 -0
- mainsequence-2.0.0/mainsequence/client/base.py +431 -0
- mainsequence-2.0.0/mainsequence/client/data_sources_interfaces/__init__.py +0 -0
- mainsequence-2.0.0/mainsequence/client/data_sources_interfaces/duckdb.py +1468 -0
- mainsequence-2.0.0/mainsequence/client/data_sources_interfaces/timescale.py +479 -0
- mainsequence-2.0.0/mainsequence/client/models_helpers.py +113 -0
- mainsequence-2.0.0/mainsequence/client/models_report_studio.py +412 -0
- mainsequence-2.0.0/mainsequence/client/models_tdag.py +2276 -0
- mainsequence-2.0.0/mainsequence/client/models_vam.py +1983 -0
- mainsequence-2.0.0/mainsequence/client/utils.py +387 -0
- mainsequence-2.0.0/mainsequence/dashboards/__init__.py +0 -0
- mainsequence-2.0.0/mainsequence/dashboards/streamlit/__init__.py +0 -0
- mainsequence-2.0.0/mainsequence/dashboards/streamlit/assets/config.toml +12 -0
- mainsequence-2.0.0/mainsequence/dashboards/streamlit/assets/favicon.png +0 -0
- mainsequence-2.0.0/mainsequence/dashboards/streamlit/assets/logo.png +0 -0
- mainsequence-2.0.0/mainsequence/dashboards/streamlit/core/__init__.py +0 -0
- mainsequence-2.0.0/mainsequence/dashboards/streamlit/core/theme.py +212 -0
- mainsequence-2.0.0/mainsequence/dashboards/streamlit/pages/__init__.py +0 -0
- mainsequence-2.0.0/mainsequence/dashboards/streamlit/scaffold.py +220 -0
- mainsequence-2.0.0/mainsequence/instrumentation/__init__.py +7 -0
- mainsequence-2.0.0/mainsequence/instrumentation/utils.py +101 -0
- mainsequence-2.0.0/mainsequence/instruments/__init__.py +1 -0
- mainsequence-2.0.0/mainsequence/instruments/data_interface/__init__.py +10 -0
- mainsequence-2.0.0/mainsequence/instruments/data_interface/data_interface.py +361 -0
- mainsequence-2.0.0/mainsequence/instruments/instruments/__init__.py +3 -0
- mainsequence-2.0.0/mainsequence/instruments/instruments/base_instrument.py +85 -0
- mainsequence-2.0.0/mainsequence/instruments/instruments/bond.py +447 -0
- mainsequence-2.0.0/mainsequence/instruments/instruments/european_option.py +74 -0
- mainsequence-2.0.0/mainsequence/instruments/instruments/interest_rate_swap.py +217 -0
- mainsequence-2.0.0/mainsequence/instruments/instruments/json_codec.py +585 -0
- mainsequence-2.0.0/mainsequence/instruments/instruments/knockout_fx_option.py +146 -0
- mainsequence-2.0.0/mainsequence/instruments/instruments/position.py +475 -0
- mainsequence-2.0.0/mainsequence/instruments/instruments/ql_fields.py +239 -0
- mainsequence-2.0.0/mainsequence/instruments/instruments/vanilla_fx_option.py +107 -0
- mainsequence-2.0.0/mainsequence/instruments/pricing_models/__init__.py +0 -0
- mainsequence-2.0.0/mainsequence/instruments/pricing_models/black_scholes.py +49 -0
- mainsequence-2.0.0/mainsequence/instruments/pricing_models/bond_pricer.py +182 -0
- mainsequence-2.0.0/mainsequence/instruments/pricing_models/fx_option_pricer.py +90 -0
- mainsequence-2.0.0/mainsequence/instruments/pricing_models/indices.py +350 -0
- mainsequence-2.0.0/mainsequence/instruments/pricing_models/knockout_fx_pricer.py +209 -0
- mainsequence-2.0.0/mainsequence/instruments/pricing_models/swap_pricer.py +502 -0
- mainsequence-2.0.0/mainsequence/instruments/settings.py +175 -0
- mainsequence-2.0.0/mainsequence/instruments/utils.py +29 -0
- mainsequence-2.0.0/mainsequence/logconf.py +284 -0
- mainsequence-2.0.0/mainsequence/reportbuilder/__init__.py +0 -0
- mainsequence-2.0.0/mainsequence/reportbuilder/__main__.py +0 -0
- mainsequence-2.0.0/mainsequence/reportbuilder/examples/ms_template_report.py +706 -0
- mainsequence-2.0.0/mainsequence/reportbuilder/model.py +713 -0
- mainsequence-2.0.0/mainsequence/reportbuilder/slide_templates.py +532 -0
- mainsequence-2.0.0/mainsequence/tdag/__init__.py +8 -0
- mainsequence-2.0.0/mainsequence/tdag/__main__.py +0 -0
- mainsequence-2.0.0/mainsequence/tdag/config.py +129 -0
- mainsequence-2.0.0/mainsequence/tdag/data_nodes/__init__.py +12 -0
- mainsequence-2.0.0/mainsequence/tdag/data_nodes/build_operations.py +751 -0
- mainsequence-2.0.0/mainsequence/tdag/data_nodes/data_nodes.py +1292 -0
- mainsequence-2.0.0/mainsequence/tdag/data_nodes/persist_managers.py +812 -0
- mainsequence-2.0.0/mainsequence/tdag/data_nodes/run_operations.py +543 -0
- mainsequence-2.0.0/mainsequence/tdag/data_nodes/utils.py +24 -0
- mainsequence-2.0.0/mainsequence/tdag/future_registry.py +25 -0
- mainsequence-2.0.0/mainsequence/tdag/utils.py +40 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/__init__.py +45 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/__main__.py +235 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/agent_interface.py +77 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/config_handling.py +86 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/contrib/__init__.py +0 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/contrib/apps/__init__.py +8 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/contrib/apps/etf_replicator_app.py +164 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/contrib/apps/generate_report.py +292 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/contrib/apps/load_external_portfolio.py +107 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/contrib/apps/news_app.py +437 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/contrib/apps/portfolio_report_app.py +91 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/contrib/apps/portfolio_table.py +95 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/contrib/apps/run_named_portfolio.py +45 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/contrib/apps/run_portfolio.py +40 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/contrib/apps/templates/base.html +147 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/contrib/apps/templates/report.html +77 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/contrib/data_nodes/__init__.py +5 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/contrib/data_nodes/external_weights.py +61 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/contrib/data_nodes/intraday_trend.py +149 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/contrib/data_nodes/market_cap.py +310 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/contrib/data_nodes/mock_signal.py +78 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/contrib/data_nodes/portfolio_replicator.py +269 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/contrib/prices/__init__.py +1 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/contrib/prices/data_nodes.py +810 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/contrib/prices/utils.py +11 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/contrib/rebalance_strategies/__init__.py +1 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/contrib/rebalance_strategies/rebalance_strategies.py +313 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/data_nodes.py +637 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/enums.py +23 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/models.py +282 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/notebook_handling.py +42 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/portfolio_interface.py +272 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/resource_factory/__init__.py +0 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/resource_factory/app_factory.py +170 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/resource_factory/base_factory.py +238 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/resource_factory/rebalance_factory.py +101 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/resource_factory/signal_factory.py +183 -0
- mainsequence-2.0.0/mainsequence/virtualfundbuilder/utils.py +381 -0
- mainsequence-2.0.0/mainsequence.egg-info/PKG-INFO +105 -0
- mainsequence-2.0.0/mainsequence.egg-info/SOURCES.txt +116 -0
- mainsequence-2.0.0/mainsequence.egg-info/dependency_links.txt +1 -0
- mainsequence-2.0.0/mainsequence.egg-info/requires.txt +49 -0
- mainsequence-2.0.0/mainsequence.egg-info/top_level.txt +1 -0
- mainsequence-2.0.0/pyproject.toml +54 -0
- mainsequence-2.0.0/setup.cfg +4 -0
- mainsequence-2.0.0/tests/test_agent.py +21 -0
- mainsequence-2.0.0/tests/test_portfolio.py +23 -0
- mainsequence-2.0.0/tests/test_replicator.py +17 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
MainSequence GmbH SDK License Agreement
|
2
|
+
This License Agreement (the "License") governs the use, modification, and distribution of the software provided by MainSequence GmbH (the "Licensor"). The software (the "Software") is provided to you under the terms of this License. By using the Software, you agree to the terms of this License.
|
3
|
+
|
4
|
+
TERMS AND CONDITIONS
|
5
|
+
0. Definitions
|
6
|
+
"Personal Use": Use by an individual for personal purposes that are not connected to any business, organization, or commercial activity.
|
7
|
+
"Internal Use": Use within a business, organization, or other entity, provided it is not made accessible to third parties or used for commercial purposes.
|
8
|
+
"Commercial Use": Use of the Software in exchange for monetary or other compensation, including hosting, offering Software as a service, selling the Software, or using it in a product or service for sale.
|
9
|
+
"License Agreement": The legally binding agreement between the Licensor and the licensee (you), subject to the terms outlined in this License.
|
10
|
+
1. Grant of License
|
11
|
+
1.1 Personal and Internal Use
|
12
|
+
The Licensor grants you a limited, non-exclusive, non-transferable, revocable license to use and modify the Software for personal or internal use only, provided that such use is strictly subject to this License Agreement and continues only while the License Agreement remains in effect.
|
13
|
+
Upon termination of this License Agreement, all rights to use the Software for personal or internal purposes shall be immediately revoked, and you must cease all use of the Software.
|
14
|
+
1.2 Modification
|
15
|
+
You are permitted to modify the Software solely for your own personal or internal use, subject to the restrictions outlined in this License Agreement.
|
16
|
+
You are not permitted to distribute, sublicense, or otherwise transfer modified or unmodified versions of the Software to any third party.
|
17
|
+
1.3 Prohibited Redistribution
|
18
|
+
You may not redistribute, sublicense, sell, lease, rent, or otherwise transfer the Software, whether in its original form or as modified by you, to any third party.
|
19
|
+
Any attempt to distribute or transfer the Software in any way, without explicit permission from MainSequence GmbH, is strictly prohibited.
|
20
|
+
2. Prohibition of Commercial Use
|
21
|
+
The Software may not be used for any commercial purposes without obtaining a separate commercial license from MainSequence GmbH.
|
22
|
+
Examples of prohibited commercial use include, but are not limited to:
|
23
|
+
Hosting or offering the Software as a service to others, either modified or unmodified.
|
24
|
+
Using the Software as part of a commercial product or service provided to customers for a fee.
|
25
|
+
Using the Software in any production environment that generates income, directly or indirectly, from its use.
|
26
|
+
3. Termination
|
27
|
+
This License Agreement will automatically terminate if you fail to comply with any of its terms.
|
28
|
+
Upon termination of this License, you must immediately cease all use of the Software, destroy all copies (modified or unmodified), and remove the Software from any devices or systems on which it is installed.
|
29
|
+
MainSequence GmbH reserves the right to terminate this License at its discretion for any violation of its terms or for any other reason.
|
30
|
+
4. Commercial License
|
31
|
+
If you wish to use the Software for commercial purposes, you must contact MainSequence GmbH to negotiate and obtain a separate commercial license. The terms of the commercial license, including any fees, will be negotiated separately from this License Agreement.
|
32
|
+
Without a valid commercial license, you are strictly prohibited from using the Software for any commercial activity.
|
33
|
+
5. Disclaimer of Warranty
|
34
|
+
THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL MAINSEQUENCE GMBH OR THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
35
|
+
|
36
|
+
6. Limitation of Liability
|
37
|
+
IN NO EVENT SHALL MAINSEQUENCE GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
38
|
+
|
39
|
+
7. Governing Law
|
40
|
+
This License Agreement shall be governed by and construed in accordance with the laws of the jurisdiction where MainSequence GmbH is located, without regard to its conflict of law provisions.
|
@@ -0,0 +1,105 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: mainsequence
|
3
|
+
Version: 2.0.0
|
4
|
+
Summary: Main Sequence SDK
|
5
|
+
Author-email: Main Sequence GmbH <dev@main-sequence.io>
|
6
|
+
License: MainSequence GmbH SDK License Agreement
|
7
|
+
This License Agreement (the "License") governs the use, modification, and distribution of the software provided by MainSequence GmbH (the "Licensor"). The software (the "Software") is provided to you under the terms of this License. By using the Software, you agree to the terms of this License.
|
8
|
+
|
9
|
+
TERMS AND CONDITIONS
|
10
|
+
0. Definitions
|
11
|
+
"Personal Use": Use by an individual for personal purposes that are not connected to any business, organization, or commercial activity.
|
12
|
+
"Internal Use": Use within a business, organization, or other entity, provided it is not made accessible to third parties or used for commercial purposes.
|
13
|
+
"Commercial Use": Use of the Software in exchange for monetary or other compensation, including hosting, offering Software as a service, selling the Software, or using it in a product or service for sale.
|
14
|
+
"License Agreement": The legally binding agreement between the Licensor and the licensee (you), subject to the terms outlined in this License.
|
15
|
+
1. Grant of License
|
16
|
+
1.1 Personal and Internal Use
|
17
|
+
The Licensor grants you a limited, non-exclusive, non-transferable, revocable license to use and modify the Software for personal or internal use only, provided that such use is strictly subject to this License Agreement and continues only while the License Agreement remains in effect.
|
18
|
+
Upon termination of this License Agreement, all rights to use the Software for personal or internal purposes shall be immediately revoked, and you must cease all use of the Software.
|
19
|
+
1.2 Modification
|
20
|
+
You are permitted to modify the Software solely for your own personal or internal use, subject to the restrictions outlined in this License Agreement.
|
21
|
+
You are not permitted to distribute, sublicense, or otherwise transfer modified or unmodified versions of the Software to any third party.
|
22
|
+
1.3 Prohibited Redistribution
|
23
|
+
You may not redistribute, sublicense, sell, lease, rent, or otherwise transfer the Software, whether in its original form or as modified by you, to any third party.
|
24
|
+
Any attempt to distribute or transfer the Software in any way, without explicit permission from MainSequence GmbH, is strictly prohibited.
|
25
|
+
2. Prohibition of Commercial Use
|
26
|
+
The Software may not be used for any commercial purposes without obtaining a separate commercial license from MainSequence GmbH.
|
27
|
+
Examples of prohibited commercial use include, but are not limited to:
|
28
|
+
Hosting or offering the Software as a service to others, either modified or unmodified.
|
29
|
+
Using the Software as part of a commercial product or service provided to customers for a fee.
|
30
|
+
Using the Software in any production environment that generates income, directly or indirectly, from its use.
|
31
|
+
3. Termination
|
32
|
+
This License Agreement will automatically terminate if you fail to comply with any of its terms.
|
33
|
+
Upon termination of this License, you must immediately cease all use of the Software, destroy all copies (modified or unmodified), and remove the Software from any devices or systems on which it is installed.
|
34
|
+
MainSequence GmbH reserves the right to terminate this License at its discretion for any violation of its terms or for any other reason.
|
35
|
+
4. Commercial License
|
36
|
+
If you wish to use the Software for commercial purposes, you must contact MainSequence GmbH to negotiate and obtain a separate commercial license. The terms of the commercial license, including any fees, will be negotiated separately from this License Agreement.
|
37
|
+
Without a valid commercial license, you are strictly prohibited from using the Software for any commercial activity.
|
38
|
+
5. Disclaimer of Warranty
|
39
|
+
THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL MAINSEQUENCE GMBH OR THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
40
|
+
|
41
|
+
6. Limitation of Liability
|
42
|
+
IN NO EVENT SHALL MAINSEQUENCE GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
43
|
+
|
44
|
+
7. Governing Law
|
45
|
+
This License Agreement shall be governed by and construed in accordance with the laws of the jurisdiction where MainSequence GmbH is located, without regard to its conflict of law provisions.
|
46
|
+
Project-URL: Homepage, https://github.com/mainsequence-sdk/mainsequence-sdk
|
47
|
+
Project-URL: Issues, https://github.com/mainsequence-sdk/mainsequence-sdk/issues
|
48
|
+
Classifier: Programming Language :: Python :: 3
|
49
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
50
|
+
Classifier: License :: OSI Approved :: MIT License
|
51
|
+
Classifier: Operating System :: OS Independent
|
52
|
+
Requires-Python: >=3.10
|
53
|
+
Description-Content-Type: text/markdown
|
54
|
+
License-File: LICENSE
|
55
|
+
Requires-Dist: cloudpickle
|
56
|
+
Requires-Dist: cryptography
|
57
|
+
Requires-Dist: fire
|
58
|
+
Requires-Dist: google-auth
|
59
|
+
Requires-Dist: joblib
|
60
|
+
Requires-Dist: matplotlib
|
61
|
+
Requires-Dist: nbconvert
|
62
|
+
Requires-Dist: numexpr
|
63
|
+
Requires-Dist: opentelemetry-api
|
64
|
+
Requires-Dist: opentelemetry-exporter-otlp
|
65
|
+
Requires-Dist: opentelemetry-sdk
|
66
|
+
Requires-Dist: pandas
|
67
|
+
Requires-Dist: pandas-market-calendars
|
68
|
+
Requires-Dist: psutil
|
69
|
+
Requires-Dist: pyarrow
|
70
|
+
Requires-Dist: pydantic
|
71
|
+
Requires-Dist: python-binance
|
72
|
+
Requires-Dist: python-dotenv
|
73
|
+
Requires-Dist: python-logstash
|
74
|
+
Requires-Dist: pyyaml
|
75
|
+
Requires-Dist: s3fs
|
76
|
+
Requires-Dist: scikit-learn
|
77
|
+
Requires-Dist: scipy
|
78
|
+
Requires-Dist: structlog
|
79
|
+
Requires-Dist: tqdm
|
80
|
+
Requires-Dist: colorama
|
81
|
+
Requires-Dist: kaleido
|
82
|
+
Requires-Dist: newspaper3k
|
83
|
+
Requires-Dist: lxml-html-clean
|
84
|
+
Requires-Dist: docstring-parser
|
85
|
+
Requires-Dist: concurrent-log-handler
|
86
|
+
Requires-Dist: duckdb
|
87
|
+
Requires-Dist: plotly
|
88
|
+
Requires-Dist: typer
|
89
|
+
Requires-Dist: QuantLib
|
90
|
+
Provides-Extra: dev
|
91
|
+
Requires-Dist: mkdocs; extra == "dev"
|
92
|
+
Requires-Dist: mkdocs-material; extra == "dev"
|
93
|
+
Requires-Dist: mkdocs-gen-files; extra == "dev"
|
94
|
+
Requires-Dist: mkdocs-literate-nav; extra == "dev"
|
95
|
+
Requires-Dist: mkdocs-autorefs; extra == "dev"
|
96
|
+
Requires-Dist: mkdocstrings[python]; extra == "dev"
|
97
|
+
Requires-Dist: mkdocs-mermaid2-plugin; extra == "dev"
|
98
|
+
Requires-Dist: pymdown-extensions; extra == "dev"
|
99
|
+
Requires-Dist: pipdeptree; extra == "dev"
|
100
|
+
Requires-Dist: pytest; extra == "dev"
|
101
|
+
Requires-Dist: pytest-freezegun; extra == "dev"
|
102
|
+
Requires-Dist: twine; extra == "dev"
|
103
|
+
Dynamic: license-file
|
104
|
+
|
105
|
+
# Main Sequence Python SDK
|
@@ -0,0 +1 @@
|
|
1
|
+
# Main Sequence Python SDK
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
from .cli import app
|
@@ -0,0 +1,157 @@
|
|
1
|
+
# mainsequence/cli/api.py
|
2
|
+
from __future__ import annotations
|
3
|
+
import os, re, subprocess, json, platform, pathlib, shlex, sys
|
4
|
+
import requests
|
5
|
+
from .config import backend_url, get_tokens, save_tokens, set_env_access
|
6
|
+
|
7
|
+
AUTH_PATHS = {
|
8
|
+
"obtain": "/auth/jwt-token/token/",
|
9
|
+
"refresh": "/auth/jwt-token/token/refresh/",
|
10
|
+
"ping": "/auth/rest-auth/user/",
|
11
|
+
}
|
12
|
+
|
13
|
+
S = requests.Session()
|
14
|
+
S.headers.update({"Content-Type": "application/json"})
|
15
|
+
|
16
|
+
class ApiError(RuntimeError): ...
|
17
|
+
class NotLoggedIn(ApiError): ...
|
18
|
+
|
19
|
+
def _full(path: str) -> str:
|
20
|
+
p = "/" + path.lstrip("/")
|
21
|
+
return backend_url() + p
|
22
|
+
|
23
|
+
def _normalize_api_path(p: str) -> str:
|
24
|
+
p = "/" + (p or "").lstrip("/")
|
25
|
+
if not re.match(r"^/(api|auth|pods|orm|user)(/|$)", p):
|
26
|
+
raise ApiError("Only /api/*, /auth/*, /pods/*, /orm/*, /user/* allowed")
|
27
|
+
return p
|
28
|
+
|
29
|
+
def _access_token() -> str | None:
|
30
|
+
t = os.environ.get("MAIN_SEQUENCE_USER_TOKEN")
|
31
|
+
if t:
|
32
|
+
return t
|
33
|
+
tok = get_tokens()
|
34
|
+
return tok.get("access")
|
35
|
+
|
36
|
+
def _refresh_token() -> str | None:
|
37
|
+
tok = get_tokens()
|
38
|
+
return tok.get("refresh")
|
39
|
+
|
40
|
+
def login(email: str, password: str) -> dict:
|
41
|
+
url = _full(AUTH_PATHS["obtain"])
|
42
|
+
payload = {"email": email, "password": password} # server expects 'email'
|
43
|
+
r = S.post(url, data=json.dumps(payload))
|
44
|
+
try:
|
45
|
+
data = r.json()
|
46
|
+
except Exception:
|
47
|
+
data = {}
|
48
|
+
if not r.ok:
|
49
|
+
msg = data.get("detail") or data.get("message") or r.text
|
50
|
+
raise ApiError(f"{msg}")
|
51
|
+
access = data.get("access") or data.get("token") or data.get("jwt") or data.get("access_token")
|
52
|
+
refresh = data.get("refresh") or data.get("refresh_token")
|
53
|
+
if not access or not refresh:
|
54
|
+
raise ApiError("Server did not return expected tokens.")
|
55
|
+
save_tokens(email, access, refresh)
|
56
|
+
set_env_access(access)
|
57
|
+
return {"username": email, "backend": backend_url()}
|
58
|
+
|
59
|
+
def refresh_access() -> str:
|
60
|
+
refresh = _refresh_token()
|
61
|
+
if not refresh:
|
62
|
+
raise NotLoggedIn("Not logged in. Run `mainsequence login <email>`.")
|
63
|
+
r = S.post(_full(AUTH_PATHS["refresh"]), data=json.dumps({"refresh": refresh}))
|
64
|
+
data = r.json() if r.headers.get("content-type","").startswith("application/json") else {}
|
65
|
+
if not r.ok:
|
66
|
+
raise NotLoggedIn(data.get("detail") or "Token refresh failed.")
|
67
|
+
access = data.get("access")
|
68
|
+
if not access:
|
69
|
+
raise NotLoggedIn("Refresh succeeded but no access token returned.")
|
70
|
+
tokens = get_tokens()
|
71
|
+
save_tokens(tokens.get("username") or "", access, refresh)
|
72
|
+
set_env_access(access)
|
73
|
+
return access
|
74
|
+
|
75
|
+
def authed(method: str, api_path: str, body: dict | None = None) -> requests.Response:
|
76
|
+
api_path = _normalize_api_path(api_path)
|
77
|
+
access = _access_token()
|
78
|
+
if not access:
|
79
|
+
# try to refresh once
|
80
|
+
access = refresh_access()
|
81
|
+
headers = {"Authorization": f"Bearer {access}"}
|
82
|
+
r = S.request(method.upper(), _full(api_path), headers=headers,
|
83
|
+
data=None if method.upper() in {"GET","HEAD"} else json.dumps(body or {}))
|
84
|
+
if r.status_code == 401:
|
85
|
+
# retry after refresh
|
86
|
+
access = refresh_access()
|
87
|
+
headers = {"Authorization": f"Bearer {access}"}
|
88
|
+
r = S.request(method.upper(), _full(api_path), headers=headers,
|
89
|
+
data=None if method.upper() in {"GET","HEAD"} else json.dumps(body or {}))
|
90
|
+
if r.status_code == 401:
|
91
|
+
raise NotLoggedIn("Not logged in.")
|
92
|
+
return r
|
93
|
+
|
94
|
+
# ---------- Helper APIs ----------
|
95
|
+
|
96
|
+
def safe_slug(s: str) -> str:
|
97
|
+
x = re.sub(r"[^a-z0-9-_]+", "-", (s or "project").lower()).strip("-")
|
98
|
+
return x[:64] or "project"
|
99
|
+
|
100
|
+
def repo_name_from_git_url(url: str | None) -> str | None:
|
101
|
+
if not url: return None
|
102
|
+
s = re.sub(r"[?#].*$", "", url.strip())
|
103
|
+
last = s.split("/")[-1] if "/" in s else s
|
104
|
+
if last.lower().endswith(".git"): last = last[:-4]
|
105
|
+
return re.sub(r"[^A-Za-z0-9._-]+", "-", last)
|
106
|
+
|
107
|
+
def deep_find_repo_url(extra) -> str | None:
|
108
|
+
if not isinstance(extra, dict): return None
|
109
|
+
cand = ["ssh_url","git_ssh_url","repo_ssh_url","git_url","repo_url","repository","url"]
|
110
|
+
for k in cand:
|
111
|
+
v = extra.get(k)
|
112
|
+
if isinstance(v, str) and (v.startswith("git@") or re.search(r"\.git($|\?)", v)):
|
113
|
+
return v
|
114
|
+
if isinstance(v, dict):
|
115
|
+
for vv in v.values():
|
116
|
+
if isinstance(vv, str) and (vv.startswith("git@") or re.search(r"\.git($|\?)", vv)):
|
117
|
+
return vv
|
118
|
+
for v in extra.values():
|
119
|
+
if isinstance(v, dict):
|
120
|
+
found = deep_find_repo_url(v)
|
121
|
+
if found: return found
|
122
|
+
return None
|
123
|
+
|
124
|
+
def get_current_user_profile() -> dict:
|
125
|
+
who = authed("GET", AUTH_PATHS["ping"])
|
126
|
+
d = who.json() if who.ok else {}
|
127
|
+
uid = d.get("id") or d.get("pk") or (d.get("user") or {}).get("id") or d.get("user_id")
|
128
|
+
if not uid:
|
129
|
+
return {}
|
130
|
+
full = authed("GET", f"/user/api/user/{uid}/")
|
131
|
+
u = full.json() if full.ok else {}
|
132
|
+
org_name = (u.get("organization") or {}).get("name") or u.get("organization_name") or ""
|
133
|
+
return {"username": u.get("username") or "", "organization": org_name}
|
134
|
+
|
135
|
+
def get_projects() -> list[dict]:
|
136
|
+
r = authed("GET", "/orm/api/pods/projects/")
|
137
|
+
# If the API shape ever changes, still try to pull a list.
|
138
|
+
if not r.ok:
|
139
|
+
raise ApiError(f"Projects fetch failed ({r.status_code}).")
|
140
|
+
data = r.json() if r.headers.get("content-type","",).startswith("application/json") else {}
|
141
|
+
if isinstance(data, list):
|
142
|
+
return data
|
143
|
+
return data.get("results") or []
|
144
|
+
|
145
|
+
def fetch_project_env_text(project_id: int | str) -> str:
|
146
|
+
r = authed("GET", f"/orm/api/pods/projects/{project_id}/get_environment/")
|
147
|
+
raw = r.json() if r.headers.get("content-type","").startswith("application/json") else r.text
|
148
|
+
if isinstance(raw, dict):
|
149
|
+
raw = raw.get("environment") or raw.get("env") or raw.get("content") or raw.get("text") or ""
|
150
|
+
return (raw or "")
|
151
|
+
|
152
|
+
def add_deploy_key(project_id: int | str, key_title: str, public_key: str) -> None:
|
153
|
+
try:
|
154
|
+
authed("POST", f"/orm/api/pods/projects/{project_id}/add_deploy_key/",
|
155
|
+
{"key_title": key_title, "public_key": public_key})
|
156
|
+
except Exception:
|
157
|
+
pass
|