x8 0.0.10__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.
- x8-0.0.10/.gitignore +133 -0
- x8-0.0.10/LICENSE +21 -0
- x8-0.0.10/PKG-INFO +44 -0
- x8-0.0.10/README.md +17 -0
- x8-0.0.10/pyproject.toml +43 -0
- x8-0.0.10/x8/common/__init__.py +0 -0
- x8-0.0.10/x8/common/azure_provider.py +192 -0
- x8-0.0.10/x8/common/google_provider.py +64 -0
- x8-0.0.10/x8/common/hosted_provider.py +120 -0
- x8-0.0.10/x8/core/__init__.py +37 -0
- x8-0.0.10/x8/core/_arg_parser.py +149 -0
- x8-0.0.10/x8/core/_async_helper.py +34 -0
- x8-0.0.10/x8/core/_component.py +206 -0
- x8-0.0.10/x8/core/_context.py +23 -0
- x8-0.0.10/x8/core/_data_accessor.py +246 -0
- x8-0.0.10/x8/core/_decorators.py +76 -0
- x8-0.0.10/x8/core/_dot_dict.py +22 -0
- x8-0.0.10/x8/core/_loader.py +905 -0
- x8-0.0.10/x8/core/_log_helper.py +4 -0
- x8-0.0.10/x8/core/_ncall.py +110 -0
- x8-0.0.10/x8/core/_operation.py +71 -0
- x8-0.0.10/x8/core/_operation_parser.py +254 -0
- x8-0.0.10/x8/core/_provider.py +97 -0
- x8-0.0.10/x8/core/_response.py +17 -0
- x8-0.0.10/x8/core/_type_converter.py +94 -0
- x8-0.0.10/x8/core/_yaml_loader.py +8 -0
- x8-0.0.10/x8/core/constants.py +1 -0
- x8-0.0.10/x8/core/data_model.py +70 -0
- x8-0.0.10/x8/core/dependency.py +31 -0
- x8-0.0.10/x8/core/exceptions.py +62 -0
- x8-0.0.10/x8/core/main.py +221 -0
- x8-0.0.10/x8/core/manifest.py +50 -0
- x8-0.0.10/x8/core/py.typed +1 -0
- x8-0.0.10/x8/core/registry.yaml +92 -0
- x8-0.0.10/x8/core/spec.py +788 -0
- x8-0.0.10/x8/core/time.py +16 -0
- x8-0.0.10/x8/ql/__init__.py +66 -0
- x8-0.0.10/x8/ql/_functions.py +379 -0
- x8-0.0.10/x8/ql/_models.py +508 -0
- x8-0.0.10/x8/ql/_parser_listener.py +772 -0
- x8-0.0.10/x8/ql/_ql_parser.py +127 -0
- x8-0.0.10/x8/ql/_query_processor.py +513 -0
- x8-0.0.10/x8/ql/exceptions.py +5 -0
- x8-0.0.10/x8/ql/generated/VerseQLLexer.interp +179 -0
- x8-0.0.10/x8/ql/generated/VerseQLLexer.py +285 -0
- x8-0.0.10/x8/ql/generated/VerseQLLexer.tokens +96 -0
- x8-0.0.10/x8/ql/generated/VerseQLParser.interp +164 -0
- x8-0.0.10/x8/ql/generated/VerseQLParser.py +8217 -0
- x8-0.0.10/x8/ql/generated/VerseQLParser.tokens +96 -0
- x8-0.0.10/x8/ql/generated/VerseQLParserListener.py +674 -0
- x8-0.0.10/x8/ql/grammar/VerseQLLexer.g4 +86 -0
- x8-0.0.10/x8/ql/grammar/VerseQLParser.g4 +250 -0
- x8-0.0.10/x8/ql/py.typed +1 -0
x8-0.0.10/.gitignore
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
pip-wheel-metadata/
|
|
24
|
+
share/python-wheels/
|
|
25
|
+
*.egg-info/
|
|
26
|
+
.installed.cfg
|
|
27
|
+
*.egg
|
|
28
|
+
MANIFEST
|
|
29
|
+
|
|
30
|
+
# PyInstaller
|
|
31
|
+
# Usually these files are written by a python script from a template
|
|
32
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
33
|
+
*.manifest
|
|
34
|
+
*.spec
|
|
35
|
+
|
|
36
|
+
# Installer logs
|
|
37
|
+
pip-log.txt
|
|
38
|
+
pip-delete-this-directory.txt
|
|
39
|
+
|
|
40
|
+
# Unit test / coverage reports
|
|
41
|
+
htmlcov/
|
|
42
|
+
.tox/
|
|
43
|
+
.nox/
|
|
44
|
+
.coverage
|
|
45
|
+
.coverage.*
|
|
46
|
+
.cache
|
|
47
|
+
nosetests.xml
|
|
48
|
+
coverage.xml
|
|
49
|
+
*.cover
|
|
50
|
+
*.py,cover
|
|
51
|
+
.hypothesis/
|
|
52
|
+
.pytest_cache/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
target/
|
|
76
|
+
|
|
77
|
+
# Jupyter Notebook
|
|
78
|
+
.ipynb_checkpoints
|
|
79
|
+
|
|
80
|
+
# IPython
|
|
81
|
+
profile_default/
|
|
82
|
+
ipython_config.py
|
|
83
|
+
|
|
84
|
+
# pyenv
|
|
85
|
+
.python-version
|
|
86
|
+
|
|
87
|
+
# pipenv
|
|
88
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
89
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
90
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
91
|
+
# install all needed dependencies.
|
|
92
|
+
#Pipfile.lock
|
|
93
|
+
|
|
94
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
|
95
|
+
__pypackages__/
|
|
96
|
+
|
|
97
|
+
# Celery stuff
|
|
98
|
+
celerybeat-schedule
|
|
99
|
+
celerybeat.pid
|
|
100
|
+
|
|
101
|
+
# SageMath parsed files
|
|
102
|
+
*.sage.py
|
|
103
|
+
|
|
104
|
+
# Environments
|
|
105
|
+
.env
|
|
106
|
+
.venv
|
|
107
|
+
env/
|
|
108
|
+
venv/
|
|
109
|
+
ENV/
|
|
110
|
+
env.bak/
|
|
111
|
+
venv.bak/
|
|
112
|
+
|
|
113
|
+
# Spyder project settings
|
|
114
|
+
.spyderproject
|
|
115
|
+
.spyproject
|
|
116
|
+
|
|
117
|
+
# Rope project settings
|
|
118
|
+
.ropeproject
|
|
119
|
+
|
|
120
|
+
# mkdocs documentation
|
|
121
|
+
/site
|
|
122
|
+
|
|
123
|
+
# mypy
|
|
124
|
+
.mypy_cache/
|
|
125
|
+
.dmypy.json
|
|
126
|
+
dmypy.json
|
|
127
|
+
|
|
128
|
+
# Pyre type checker
|
|
129
|
+
.pyre/
|
|
130
|
+
|
|
131
|
+
misc/
|
|
132
|
+
tmp_results/
|
|
133
|
+
.DS_Store
|
x8-0.0.10/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 x0
|
|
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.
|
x8-0.0.10/PKG-INFO
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: x8
|
|
3
|
+
Version: 0.0.10
|
|
4
|
+
Summary: x8 client
|
|
5
|
+
Project-URL: Homepage, https://github.com/rapidverse/x8
|
|
6
|
+
Project-URL: Repository, https://github.com/rapidverse/x8
|
|
7
|
+
Project-URL: Documentation, https://github.com/rapidverse/x8
|
|
8
|
+
Author-email: x8 <slenin@gmail.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: client,x8
|
|
12
|
+
Requires-Python: >=3.9
|
|
13
|
+
Requires-Dist: antlr4-python3-runtime
|
|
14
|
+
Requires-Dist: docstring-parser
|
|
15
|
+
Requires-Dist: pydantic
|
|
16
|
+
Requires-Dist: pyyaml
|
|
17
|
+
Provides-Extra: dev
|
|
18
|
+
Requires-Dist: flake8; extra == 'dev'
|
|
19
|
+
Requires-Dist: ipykernel; extra == 'dev'
|
|
20
|
+
Requires-Dist: jupyter; extra == 'dev'
|
|
21
|
+
Requires-Dist: mypy; extra == 'dev'
|
|
22
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
23
|
+
Requires-Dist: pytest-asyncio; extra == 'dev'
|
|
24
|
+
Requires-Dist: pytest-cov; extra == 'dev'
|
|
25
|
+
Requires-Dist: types-pyyaml; extra == 'dev'
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# x8
|
|
29
|
+
|
|
30
|
+
x8 is a Python client library.
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install x8
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## CLI
|
|
39
|
+
|
|
40
|
+
This package installs the `x8` CLI entrypoint:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
x8 --help
|
|
44
|
+
```
|
x8-0.0.10/README.md
ADDED
x8-0.0.10/pyproject.toml
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "x8"
|
|
3
|
+
version = "0.0.10"
|
|
4
|
+
description = "x8 client"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = { text = "MIT" }
|
|
7
|
+
authors = [{ name = "x8", email = "slenin@gmail.com" }]
|
|
8
|
+
keywords = ["x8", "client"]
|
|
9
|
+
requires-python = ">=3.9"
|
|
10
|
+
|
|
11
|
+
dependencies = [
|
|
12
|
+
"PyYAML",
|
|
13
|
+
"pydantic",
|
|
14
|
+
"docstring-parser",
|
|
15
|
+
"antlr4-python3-runtime",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[project.optional-dependencies]
|
|
19
|
+
dev = [
|
|
20
|
+
"mypy",
|
|
21
|
+
"flake8",
|
|
22
|
+
"pytest",
|
|
23
|
+
"pytest-asyncio",
|
|
24
|
+
"pytest-cov",
|
|
25
|
+
"types-PyYAML",
|
|
26
|
+
"jupyter",
|
|
27
|
+
"ipykernel",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Homepage = "https://github.com/rapidverse/x8"
|
|
32
|
+
Repository = "https://github.com/rapidverse/x8"
|
|
33
|
+
Documentation = "https://github.com/rapidverse/x8"
|
|
34
|
+
|
|
35
|
+
[project.scripts]
|
|
36
|
+
x8 = "x8.core.main:main"
|
|
37
|
+
|
|
38
|
+
[build-system]
|
|
39
|
+
requires = ["hatchling"]
|
|
40
|
+
build-backend = "hatchling.build"
|
|
41
|
+
|
|
42
|
+
[tool.hatch.build.targets.wheel]
|
|
43
|
+
packages = ["x8"]
|
|
File without changes
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from ..core import Provider
|
|
4
|
+
from ..core.exceptions import BadRequestError
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AzureProvider(Provider):
|
|
8
|
+
credential_type: str | None
|
|
9
|
+
tenant_id: str | None
|
|
10
|
+
client_id: str | None
|
|
11
|
+
client_secret: str | None
|
|
12
|
+
certificate_path: str | None
|
|
13
|
+
|
|
14
|
+
_credential: Any
|
|
15
|
+
_acredential: Any
|
|
16
|
+
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
credential_type: str | None = "default",
|
|
20
|
+
tenant_id: str | None = None,
|
|
21
|
+
client_id: str | None = None,
|
|
22
|
+
client_secret: str | None = None,
|
|
23
|
+
certificate_path: str | None = None,
|
|
24
|
+
**kwargs,
|
|
25
|
+
):
|
|
26
|
+
self.credential_type = credential_type
|
|
27
|
+
self.tenant_id = tenant_id
|
|
28
|
+
self.client_id = client_id
|
|
29
|
+
self.client_secret = client_secret
|
|
30
|
+
self.certificate_path = certificate_path
|
|
31
|
+
self._credential = None
|
|
32
|
+
self._acredential = None
|
|
33
|
+
super().__init__(**kwargs)
|
|
34
|
+
|
|
35
|
+
def _get_credential(self):
|
|
36
|
+
if self._credential:
|
|
37
|
+
return self._credential
|
|
38
|
+
credential_type = self.credential_type
|
|
39
|
+
credential = None
|
|
40
|
+
if credential_type == "default":
|
|
41
|
+
from azure.identity import DefaultAzureCredential
|
|
42
|
+
|
|
43
|
+
credential = DefaultAzureCredential()
|
|
44
|
+
|
|
45
|
+
elif credential_type == "client_secret":
|
|
46
|
+
from azure.identity import ClientSecretCredential
|
|
47
|
+
|
|
48
|
+
credential = ClientSecretCredential(
|
|
49
|
+
tenant_id=self.tenant_id,
|
|
50
|
+
client_id=self.client_id,
|
|
51
|
+
client_secret=self.client_secret,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
elif credential_type == "certificate":
|
|
55
|
+
from azure.identity import CertificateCredential
|
|
56
|
+
|
|
57
|
+
credential = CertificateCredential(
|
|
58
|
+
tenant_id=self.tenant_id,
|
|
59
|
+
client_id=self.client_id,
|
|
60
|
+
certificate_path=self.certificate_path,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
elif credential_type == "azure_cli":
|
|
64
|
+
from azure.identity import AzureCliCredential
|
|
65
|
+
|
|
66
|
+
credential = AzureCliCredential()
|
|
67
|
+
|
|
68
|
+
elif credential_type == "shared_token_cache":
|
|
69
|
+
from azure.identity import SharedTokenCacheCredential
|
|
70
|
+
|
|
71
|
+
credential = SharedTokenCacheCredential()
|
|
72
|
+
|
|
73
|
+
elif credential_type == "managed_identity":
|
|
74
|
+
from azure.identity import ManagedIdentityCredential
|
|
75
|
+
|
|
76
|
+
credential = ManagedIdentityCredential()
|
|
77
|
+
|
|
78
|
+
self._credential = credential
|
|
79
|
+
return credential
|
|
80
|
+
|
|
81
|
+
def _aget_credential(self):
|
|
82
|
+
if self._acredential:
|
|
83
|
+
return self._acredential
|
|
84
|
+
credential_type = self.credential_type
|
|
85
|
+
credential = None
|
|
86
|
+
if credential_type == "default":
|
|
87
|
+
from azure.identity.aio import DefaultAzureCredential
|
|
88
|
+
|
|
89
|
+
credential = DefaultAzureCredential()
|
|
90
|
+
|
|
91
|
+
if credential_type == "client_secret":
|
|
92
|
+
from azure.identity.aio import ClientSecretCredential
|
|
93
|
+
|
|
94
|
+
credential = ClientSecretCredential(
|
|
95
|
+
tenant_id=self.tenant_id,
|
|
96
|
+
client_id=self.client_id,
|
|
97
|
+
client_secret=self.client_secret,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
if credential_type == "certificate":
|
|
101
|
+
from azure.identity.aio import CertificateCredential
|
|
102
|
+
|
|
103
|
+
credential = CertificateCredential(
|
|
104
|
+
tenant_id=self.tenant_id,
|
|
105
|
+
client_id=self.client_id,
|
|
106
|
+
certificate_path=self.certificate_path,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
if credential_type == "azure_cli":
|
|
110
|
+
from azure.identity.aio import AzureCliCredential
|
|
111
|
+
|
|
112
|
+
credential = AzureCliCredential()
|
|
113
|
+
|
|
114
|
+
if credential_type == "shared_token_cache":
|
|
115
|
+
from azure.identity.aio import SharedTokenCacheCredential
|
|
116
|
+
|
|
117
|
+
credential = SharedTokenCacheCredential()
|
|
118
|
+
|
|
119
|
+
if credential_type == "managed_identity":
|
|
120
|
+
from azure.identity.aio import ManagedIdentityCredential
|
|
121
|
+
|
|
122
|
+
credential = ManagedIdentityCredential()
|
|
123
|
+
|
|
124
|
+
self._acredential = credential
|
|
125
|
+
return credential
|
|
126
|
+
|
|
127
|
+
def _get_default_subscription_id(self) -> str:
|
|
128
|
+
from azure.mgmt.resource import SubscriptionClient
|
|
129
|
+
|
|
130
|
+
sub_client = SubscriptionClient(credential=self._get_credential())
|
|
131
|
+
subs = sub_client.subscriptions.list()
|
|
132
|
+
if not subs:
|
|
133
|
+
raise BadRequestError(
|
|
134
|
+
"No subscriptions found for the given credentials."
|
|
135
|
+
)
|
|
136
|
+
sub = next(sub_client.subscriptions.list())
|
|
137
|
+
return sub.subscription_id
|
|
138
|
+
|
|
139
|
+
def _ensure_resource_group(
|
|
140
|
+
self,
|
|
141
|
+
resource_group: str,
|
|
142
|
+
location: str = "westus2",
|
|
143
|
+
subscription_id: str | None = None,
|
|
144
|
+
) -> None:
|
|
145
|
+
from azure.core.exceptions import ResourceNotFoundError
|
|
146
|
+
from azure.mgmt.resource import ResourceManagementClient
|
|
147
|
+
|
|
148
|
+
rg_client = ResourceManagementClient(
|
|
149
|
+
credential=self._get_credential(),
|
|
150
|
+
subscription_id=subscription_id
|
|
151
|
+
or self._get_default_subscription_id(),
|
|
152
|
+
)
|
|
153
|
+
try:
|
|
154
|
+
rg_client.resource_groups.get(resource_group)
|
|
155
|
+
except ResourceNotFoundError:
|
|
156
|
+
rg_client.resource_groups.create_or_update(
|
|
157
|
+
resource_group, {"location": location}
|
|
158
|
+
)
|
|
159
|
+
print(f"Created resource group: {resource_group}")
|
|
160
|
+
|
|
161
|
+
def _delete_resource_group_if_empty(
|
|
162
|
+
self,
|
|
163
|
+
resource_group: str,
|
|
164
|
+
subscription_id: str | None = None,
|
|
165
|
+
) -> None:
|
|
166
|
+
from azure.core.exceptions import ResourceNotFoundError
|
|
167
|
+
from azure.mgmt.resource import ResourceManagementClient
|
|
168
|
+
|
|
169
|
+
rg_client = ResourceManagementClient(
|
|
170
|
+
credential=self._credential,
|
|
171
|
+
subscription_id=subscription_id
|
|
172
|
+
or self._get_default_subscription_id(),
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
# Check if the resource group is empty before deleting
|
|
176
|
+
resources = list(
|
|
177
|
+
rg_client.resources.list_by_resource_group(resource_group)
|
|
178
|
+
)
|
|
179
|
+
for resource in resources:
|
|
180
|
+
print(f"Found resource in group: {resource.name}")
|
|
181
|
+
if resources:
|
|
182
|
+
print(
|
|
183
|
+
f"Resource group {resource_group} is not empty; "
|
|
184
|
+
"skipping deletion."
|
|
185
|
+
)
|
|
186
|
+
return
|
|
187
|
+
try:
|
|
188
|
+
operation = rg_client.resource_groups.begin_delete(resource_group)
|
|
189
|
+
operation.result()
|
|
190
|
+
print(f"Deleted resource group: {resource_group}")
|
|
191
|
+
except ResourceNotFoundError:
|
|
192
|
+
print(f"Resource group {resource_group} not found to delete.")
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from ..core import Provider
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class GoogleProvider(Provider):
|
|
8
|
+
service_account_info: str | None
|
|
9
|
+
service_account_file: str | None
|
|
10
|
+
access_token: str | None
|
|
11
|
+
|
|
12
|
+
_credentials: Any
|
|
13
|
+
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
service_account_info: str | None = None,
|
|
17
|
+
service_account_file: str | None = None,
|
|
18
|
+
access_token: str | None = None,
|
|
19
|
+
**kwargs,
|
|
20
|
+
):
|
|
21
|
+
self.service_account_info = service_account_info
|
|
22
|
+
self.service_account_file = service_account_file
|
|
23
|
+
self.access_token = access_token
|
|
24
|
+
self._credentials = None
|
|
25
|
+
super().__init__(**kwargs)
|
|
26
|
+
|
|
27
|
+
def _get_credentials(self):
|
|
28
|
+
if self._credentials:
|
|
29
|
+
return self._credentials
|
|
30
|
+
from google.oauth2 import service_account
|
|
31
|
+
|
|
32
|
+
if self.service_account_info is not None:
|
|
33
|
+
service_account_info = (
|
|
34
|
+
json.loads(self.service_account_info)
|
|
35
|
+
if isinstance(self.service_account_info, str)
|
|
36
|
+
else self.service_account_info
|
|
37
|
+
)
|
|
38
|
+
self._credentials = (
|
|
39
|
+
service_account.Credentials.from_service_account_info(
|
|
40
|
+
service_account_info
|
|
41
|
+
)
|
|
42
|
+
)
|
|
43
|
+
elif self.service_account_file is not None:
|
|
44
|
+
self._credentials = (
|
|
45
|
+
service_account.Credentials.from_service_account_file(
|
|
46
|
+
self.service_account_file
|
|
47
|
+
)
|
|
48
|
+
)
|
|
49
|
+
elif self.access_token is not None:
|
|
50
|
+
from google.auth.credentials import Credentials
|
|
51
|
+
|
|
52
|
+
self._credentials = Credentials(self.access_token)
|
|
53
|
+
return self._credentials
|
|
54
|
+
|
|
55
|
+
def _get_project_or_default(self, project: str | None) -> str:
|
|
56
|
+
if project:
|
|
57
|
+
return project
|
|
58
|
+
return self._get_default_project()
|
|
59
|
+
|
|
60
|
+
def _get_default_project(self) -> str:
|
|
61
|
+
import google.auth
|
|
62
|
+
|
|
63
|
+
_, project = google.auth.default()
|
|
64
|
+
return project
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
import httpx
|
|
4
|
+
|
|
5
|
+
from ..core import Context, DataModel, Operation, Provider, Response
|
|
6
|
+
from ..core.exceptions import (
|
|
7
|
+
BadRequestError,
|
|
8
|
+
ConflictError,
|
|
9
|
+
ForbiddenError,
|
|
10
|
+
InternalError,
|
|
11
|
+
NotFoundError,
|
|
12
|
+
NotModified,
|
|
13
|
+
NotSupportedError,
|
|
14
|
+
PreconditionFailedError,
|
|
15
|
+
UnauthorizedError,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class PostRequest(DataModel):
|
|
20
|
+
operation: Operation | None
|
|
21
|
+
context: Context | None
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class HostedProvider(Provider):
|
|
25
|
+
endpoint: str
|
|
26
|
+
credential: str | None
|
|
27
|
+
timeout: float | None
|
|
28
|
+
nparams: dict[str, Any]
|
|
29
|
+
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
endpoint: str,
|
|
33
|
+
credential: str | None = None,
|
|
34
|
+
timeout: float | None = 60,
|
|
35
|
+
nparams: dict[str, Any] = dict(),
|
|
36
|
+
**kwargs,
|
|
37
|
+
):
|
|
38
|
+
"""Initialize.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
endpoint:
|
|
42
|
+
HTTP endpoint.
|
|
43
|
+
credential:
|
|
44
|
+
API credential.
|
|
45
|
+
timeout:
|
|
46
|
+
HTTP timeout. Defaults to 60 seconds.
|
|
47
|
+
nparams:
|
|
48
|
+
Native params to httpx client.
|
|
49
|
+
"""
|
|
50
|
+
self.endpoint = endpoint
|
|
51
|
+
self.credential = credential
|
|
52
|
+
self.timeout = timeout
|
|
53
|
+
self.nparams = nparams
|
|
54
|
+
|
|
55
|
+
def __run__(
|
|
56
|
+
self,
|
|
57
|
+
operation: Operation | None = None,
|
|
58
|
+
context: Context | None = None,
|
|
59
|
+
**kwargs,
|
|
60
|
+
) -> Any:
|
|
61
|
+
headers = {
|
|
62
|
+
"Authorization": f"Bearer {self.credential}",
|
|
63
|
+
"Content-Type": "application/json",
|
|
64
|
+
}
|
|
65
|
+
request = PostRequest(operation=operation, context=context)
|
|
66
|
+
with httpx.Client(timeout=self.timeout) as client:
|
|
67
|
+
try:
|
|
68
|
+
response = client.post(
|
|
69
|
+
self.endpoint,
|
|
70
|
+
json=request.to_dict(),
|
|
71
|
+
headers=headers,
|
|
72
|
+
)
|
|
73
|
+
response.raise_for_status()
|
|
74
|
+
return Response(**response.json())
|
|
75
|
+
except httpx.HTTPStatusError as e:
|
|
76
|
+
raise self.handle_http_error(e.response)
|
|
77
|
+
|
|
78
|
+
async def __arun__(
|
|
79
|
+
self,
|
|
80
|
+
operation: Operation | None = None,
|
|
81
|
+
context: Context | None = None,
|
|
82
|
+
**kwargs,
|
|
83
|
+
) -> Any:
|
|
84
|
+
headers = {
|
|
85
|
+
"Authorization": f"Bearer {self.credential}",
|
|
86
|
+
"Content-Type": "application/json",
|
|
87
|
+
}
|
|
88
|
+
request = PostRequest(operation=operation, context=context)
|
|
89
|
+
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
|
90
|
+
try:
|
|
91
|
+
response = await client.post(
|
|
92
|
+
self.endpoint,
|
|
93
|
+
json=request.to_dict(),
|
|
94
|
+
headers=headers,
|
|
95
|
+
)
|
|
96
|
+
response.raise_for_status()
|
|
97
|
+
return Response(**response.json())
|
|
98
|
+
except httpx.HTTPStatusError as e:
|
|
99
|
+
raise self.handle_http_error(e.response)
|
|
100
|
+
|
|
101
|
+
def handle_http_error(self, response: httpx.Response) -> Exception:
|
|
102
|
+
if response.status_code == 304:
|
|
103
|
+
return NotModified(response.text)
|
|
104
|
+
if response.status_code == 400:
|
|
105
|
+
return BadRequestError(response.text)
|
|
106
|
+
elif response.status_code == 401:
|
|
107
|
+
return UnauthorizedError(response.text)
|
|
108
|
+
elif response.status_code == 403:
|
|
109
|
+
return ForbiddenError(response.text)
|
|
110
|
+
elif response.status_code == 404:
|
|
111
|
+
return NotFoundError(response.text)
|
|
112
|
+
elif response.status_code == 409:
|
|
113
|
+
return ConflictError(response.text)
|
|
114
|
+
elif response.status_code == 412:
|
|
115
|
+
return PreconditionFailedError(response.text)
|
|
116
|
+
elif response.status_code == 415:
|
|
117
|
+
return NotSupportedError(response.text)
|
|
118
|
+
elif response.status_code == 500:
|
|
119
|
+
return InternalError(response.text)
|
|
120
|
+
return InternalError(f"{response.status_code}: {response.text}")
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from ._arg_parser import ArgParser
|
|
2
|
+
from ._component import Component
|
|
3
|
+
from ._context import Context, RunContext
|
|
4
|
+
from ._data_accessor import DataAccessor
|
|
5
|
+
from ._decorators import component, operation
|
|
6
|
+
from ._dot_dict import DotDict
|
|
7
|
+
from ._loader import Loader
|
|
8
|
+
from ._log_helper import warn
|
|
9
|
+
from ._ncall import NCall
|
|
10
|
+
from ._operation import Operation
|
|
11
|
+
from ._operation_parser import OperationParser
|
|
12
|
+
from ._provider import Provider
|
|
13
|
+
from ._response import Response
|
|
14
|
+
from ._type_converter import TypeConverter
|
|
15
|
+
from .data_model import DataModel
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"ArgParser",
|
|
19
|
+
"Component",
|
|
20
|
+
"ComponentContext",
|
|
21
|
+
"Context",
|
|
22
|
+
"DataModel",
|
|
23
|
+
"DataAccessor",
|
|
24
|
+
"DotDict",
|
|
25
|
+
"Loader",
|
|
26
|
+
"NCall",
|
|
27
|
+
"Operation",
|
|
28
|
+
"OperationParser",
|
|
29
|
+
"Provider",
|
|
30
|
+
"ProviderContext",
|
|
31
|
+
"RunContext",
|
|
32
|
+
"Response",
|
|
33
|
+
"TypeConverter",
|
|
34
|
+
"component",
|
|
35
|
+
"operation",
|
|
36
|
+
"warn",
|
|
37
|
+
]
|