tine 0.0.5__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.
- tine-0.0.5/PKG-INFO +58 -0
- tine-0.0.5/gauge/__init__.py +5 -0
- tine-0.0.5/gauge/cli/__init__.py +0 -0
- tine-0.0.5/gauge/cli/console.py +39 -0
- tine-0.0.5/gauge/cli/deploy.py +145 -0
- tine-0.0.5/gauge/cli/main.py +50 -0
- tine-0.0.5/gauge/cli/tests/__init__.py +0 -0
- tine-0.0.5/gauge/cli/tests/sample.py +13 -0
- tine-0.0.5/gauge/cli/tests/test_deploy.py +74 -0
- tine-0.0.5/gauge/cli/tests/test_main.py +33 -0
- tine-0.0.5/gauge/sdk/__init__.py +0 -0
- tine-0.0.5/gauge/sdk/config.py +8 -0
- tine-0.0.5/gauge/sdk/main.py +22 -0
- tine-0.0.5/gauge/sdk/tests/__init__.py +0 -0
- tine-0.0.5/gauge/sdk/tests/test_sdk.py +37 -0
- tine-0.0.5/pyproject.toml +113 -0
- tine-0.0.5/setup.cfg +4 -0
- tine-0.0.5/tine.egg-info/PKG-INFO +58 -0
- tine-0.0.5/tine.egg-info/SOURCES.txt +21 -0
- tine-0.0.5/tine.egg-info/dependency_links.txt +1 -0
- tine-0.0.5/tine.egg-info/entry_points.txt +2 -0
- tine-0.0.5/tine.egg-info/requires.txt +40 -0
- tine-0.0.5/tine.egg-info/top_level.txt +1 -0
tine-0.0.5/PKG-INFO
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: tine
|
|
3
|
+
Version: 0.0.5
|
|
4
|
+
Summary: Effortless serverless, in your own cloud
|
|
5
|
+
Author-email: Caelean Barnes <caeleanb@gmail.com>, Evan Doyle <evanmdoyle@gmail.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/gauge-sh/gauge-serverless
|
|
7
|
+
Project-URL: Issues, https://github.com/gauge-sh/tach/gauge-serverless
|
|
8
|
+
Keywords: python,lambda,aws,serverless,fastapi
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Programming Language :: Python
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
24
|
+
Requires-Python: >=3.8
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
Requires-Dist: rich~=13.0
|
|
27
|
+
Requires-Dist: pydantic~=2.0
|
|
28
|
+
Requires-Dist: stdlib-list>=0.10.0; python_version < "3.10"
|
|
29
|
+
Requires-Dist: eval-type-backport>=0.2.0; python_version < "3.10"
|
|
30
|
+
Requires-Dist: boto3~=1.34.145
|
|
31
|
+
Requires-Dist: requests~=2.32.3
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: pyyaml==6.0.1; extra == "dev"
|
|
34
|
+
Requires-Dist: pydantic==2.8.2; python_version > "3.7" and extra == "dev"
|
|
35
|
+
Requires-Dist: rich==13.7.1; extra == "dev"
|
|
36
|
+
Requires-Dist: fastapi==0.111.1; extra == "dev"
|
|
37
|
+
Requires-Dist: boto3-stubs-lite==1.34.145; extra == "dev"
|
|
38
|
+
Requires-Dist: boto3-stubs==1.34.145; extra == "dev"
|
|
39
|
+
Requires-Dist: tach==0.8.1; extra == "dev"
|
|
40
|
+
Requires-Dist: pip==24.0; extra == "dev"
|
|
41
|
+
Requires-Dist: pyright==1.1.372; extra == "dev"
|
|
42
|
+
Requires-Dist: ruff==0.5.2; extra == "dev"
|
|
43
|
+
Requires-Dist: setuptools==69.5.1; python_version > "3.7" and extra == "dev"
|
|
44
|
+
Requires-Dist: twine==5.1.1; python_version > "3.7" and extra == "dev"
|
|
45
|
+
Requires-Dist: build==1.2.1; python_version > "3.7" and extra == "dev"
|
|
46
|
+
Requires-Dist: pytest==8.2.2; python_version > "3.7" and extra == "dev"
|
|
47
|
+
Requires-Dist: pytest-mock==3.14.0; python_version > "3.7" and extra == "dev"
|
|
48
|
+
Requires-Dist: coverage==7.6.0; python_version > "3.7" and extra == "dev"
|
|
49
|
+
Requires-Dist: botocore==1.33.13; python_version == "3.7" and extra == "dev"
|
|
50
|
+
Requires-Dist: boto3-stubs-lite==1.33.13; python_version == "3.7" and extra == "dev"
|
|
51
|
+
Requires-Dist: boto3-stubs==1.33.13; python_version == "3.7" and extra == "dev"
|
|
52
|
+
Requires-Dist: pydantic==2.5.3; python_version == "3.7" and extra == "dev"
|
|
53
|
+
Requires-Dist: setuptools==47.1.0; python_version == "3.7" and extra == "dev"
|
|
54
|
+
Requires-Dist: twine==4.0.2; python_version == "3.7" and extra == "dev"
|
|
55
|
+
Requires-Dist: build==1.1.1; python_version == "3.7" and extra == "dev"
|
|
56
|
+
Requires-Dist: pytest==7.4.4; python_version == "3.7" and extra == "dev"
|
|
57
|
+
Requires-Dist: pytest-mock==3.11.1; python_version == "3.7" and extra == "dev"
|
|
58
|
+
Requires-Dist: coverage==7.2.7; python_version == "3.7" and extra == "dev"
|
|
File without changes
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from contextlib import contextmanager
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from rich.console import Console
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from collections.abc import Generator
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@contextmanager
|
|
14
|
+
def log_task(start_message: str, end_message: str) -> Generator[None, None, None]:
|
|
15
|
+
console = Console()
|
|
16
|
+
with console.status(
|
|
17
|
+
f" {start_message}", spinner="aesthetic", spinner_style="blue"
|
|
18
|
+
):
|
|
19
|
+
try:
|
|
20
|
+
# Before entering the block
|
|
21
|
+
yield
|
|
22
|
+
finally:
|
|
23
|
+
# After exiting the block
|
|
24
|
+
# Format the current time to include leading zeros (HH:MM:SS)
|
|
25
|
+
timestamp_str = datetime.now().strftime("[%H:%M:%S]")
|
|
26
|
+
console.print(
|
|
27
|
+
f"{timestamp_str} [bright_green]✓[/bright_green] {end_message}",
|
|
28
|
+
highlight=False,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def log_error(message: str) -> None:
|
|
33
|
+
console = Console()
|
|
34
|
+
console.print(f"[bright_red]✗ Error[/bright_red]: {message}")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def log_warning(message: str) -> None:
|
|
38
|
+
console = Console()
|
|
39
|
+
console.print(f"[yellow] Warning[/yellow]: {message}")
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import importlib.util
|
|
4
|
+
import inspect
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
import sys
|
|
8
|
+
import tempfile
|
|
9
|
+
import uuid
|
|
10
|
+
import zipfile
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from time import sleep
|
|
13
|
+
from typing import Dict, TypedDict
|
|
14
|
+
|
|
15
|
+
import requests
|
|
16
|
+
from rich.console import Console
|
|
17
|
+
|
|
18
|
+
from gauge.cli.console import log_error, log_task
|
|
19
|
+
|
|
20
|
+
API_URL = os.environ.get("GAUGE_API_URL", "http://localhost:8000")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class DeployType(TypedDict):
|
|
24
|
+
module: str | None
|
|
25
|
+
reference: str
|
|
26
|
+
function: str
|
|
27
|
+
python_version: str
|
|
28
|
+
dependencies: list[str]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
DeployConfigType = Dict[str, DeployType]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class DeployHandler:
|
|
35
|
+
def __init__(self, file_paths: list[str], deploy_name: str = "") -> None:
|
|
36
|
+
self.file_paths = {Path(file_path) for file_path in file_paths}
|
|
37
|
+
if not deploy_name:
|
|
38
|
+
deploy_name = str(uuid.uuid4())
|
|
39
|
+
self.deploy_name = deploy_name
|
|
40
|
+
|
|
41
|
+
def validate_file_paths(self) -> None:
|
|
42
|
+
errored = False
|
|
43
|
+
for file_path in self.file_paths:
|
|
44
|
+
if not file_path.exists():
|
|
45
|
+
errored = True
|
|
46
|
+
log_error(f"{file_path} does not exist")
|
|
47
|
+
elif not file_path.is_file():
|
|
48
|
+
errored = True
|
|
49
|
+
log_error(f"{file_path} is not a file")
|
|
50
|
+
elif file_path.suffix.lower() != ".py":
|
|
51
|
+
errored = True
|
|
52
|
+
log_error(f"{file_path} is not a python file")
|
|
53
|
+
if errored:
|
|
54
|
+
sys.exit(1)
|
|
55
|
+
|
|
56
|
+
def bundle(self, temp_dir: str) -> Path:
|
|
57
|
+
with log_task(start_message="Bundling...", end_message="Project bundled"):
|
|
58
|
+
zip_filename = f"{self.deploy_name}.zip"
|
|
59
|
+
zip_path = Path(temp_dir) / zip_filename
|
|
60
|
+
|
|
61
|
+
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zipf:
|
|
62
|
+
for file_path in self.file_paths:
|
|
63
|
+
zipf.write(file_path)
|
|
64
|
+
return zip_path
|
|
65
|
+
|
|
66
|
+
def upload(self, zip_path: Path, deployments: DeployConfigType) -> None:
|
|
67
|
+
print(deployments)
|
|
68
|
+
gauge_client_id = os.environ.get("GAUGE_CLIENT_ID") or input(
|
|
69
|
+
"Input your GAUGE_CLIENT_ID: "
|
|
70
|
+
)
|
|
71
|
+
with log_task(
|
|
72
|
+
start_message="Uploading bundle...", end_message="Bundle uploaded"
|
|
73
|
+
):
|
|
74
|
+
with open(zip_path, "rb") as zip_file:
|
|
75
|
+
files = {"file": zip_file, "json_data": (None, json.dumps(deployments))}
|
|
76
|
+
resp = requests.post(
|
|
77
|
+
API_URL + "/v0.1/deploy/",
|
|
78
|
+
headers={"GAUGE_CLIENT_ID": gauge_client_id},
|
|
79
|
+
files=files,
|
|
80
|
+
)
|
|
81
|
+
if resp.status_code != 200:
|
|
82
|
+
print(resp.status_code, resp.content)
|
|
83
|
+
log_error("Failed to trigger the deploy")
|
|
84
|
+
sys.exit(1)
|
|
85
|
+
|
|
86
|
+
def retrieve(self):
|
|
87
|
+
with log_task(
|
|
88
|
+
start_message="Checking deploy status...", end_message="Status updated"
|
|
89
|
+
):
|
|
90
|
+
status = "pending"
|
|
91
|
+
while status == "pending":
|
|
92
|
+
resp = requests.get(API_URL)
|
|
93
|
+
sleep(0.1)
|
|
94
|
+
if resp.status_code == 200:
|
|
95
|
+
deployment_data = resp.json()
|
|
96
|
+
for deployment in deployment_data["deployments"]:
|
|
97
|
+
if deployment["name"] == self.deploy_name[:8]:
|
|
98
|
+
status = deployment["status"]
|
|
99
|
+
if status == "error":
|
|
100
|
+
log_error(deployment["debug"])
|
|
101
|
+
elif status == "deployed":
|
|
102
|
+
return deployment.get("deploy_url", "[deployment_url]")
|
|
103
|
+
break
|
|
104
|
+
else:
|
|
105
|
+
sleep(3)
|
|
106
|
+
|
|
107
|
+
def register_deployments(self) -> DeployConfigType:
|
|
108
|
+
results = {}
|
|
109
|
+
for file_path in self.file_paths:
|
|
110
|
+
module_name = str(file_path).replace(os.path.sep, ".").replace(".py", "")
|
|
111
|
+
spec = importlib.util.spec_from_file_location(file_path.stem, file_path)
|
|
112
|
+
if spec and spec.loader:
|
|
113
|
+
module = importlib.util.module_from_spec(spec)
|
|
114
|
+
spec.loader.exec_module(module)
|
|
115
|
+
for name, obj in inspect.getmembers(module):
|
|
116
|
+
if inspect.isfunction(obj) and hasattr(obj, "_gauge_register"):
|
|
117
|
+
try:
|
|
118
|
+
name, config = obj._gauge_register() # type: ignore
|
|
119
|
+
if name in results:
|
|
120
|
+
raise ValueError(f"Duplicate endpoint {name}")
|
|
121
|
+
results[name] = {
|
|
122
|
+
"module": module_name,
|
|
123
|
+
"reference": f"{module_name}:{config['function']}",
|
|
124
|
+
**config,
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
except Exception as e:
|
|
128
|
+
print(f"Error calling _gauge_register on {name}: {e}")
|
|
129
|
+
break
|
|
130
|
+
else:
|
|
131
|
+
print(f"Couldn't load module from {file_path}")
|
|
132
|
+
return results # type: ignore
|
|
133
|
+
|
|
134
|
+
def deploy(self):
|
|
135
|
+
console = Console()
|
|
136
|
+
console.print(
|
|
137
|
+
f"Deploying [bold white]"
|
|
138
|
+
f"[bold green] as [bold white]{self.deploy_name}[bold green]...",
|
|
139
|
+
)
|
|
140
|
+
self.validate_file_paths()
|
|
141
|
+
deployments = self.register_deployments()
|
|
142
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
143
|
+
zip_path = self.bundle(temp_dir)
|
|
144
|
+
self.upload(zip_path, deployments)
|
|
145
|
+
console.print(f"[bold white]{self.deploy_name[:8]} [bold green]deployed!")
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
|
|
5
|
+
from gauge.cli.deploy import DeployHandler
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def deploy(file_path_str: str) -> None:
|
|
9
|
+
file_paths = [path.strip() for path in file_path_str.split(",")]
|
|
10
|
+
DeployHandler(file_paths=file_paths, deploy_name="test").deploy()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def status() -> None:
|
|
14
|
+
"""Check the status of the application."""
|
|
15
|
+
print("Checking the status of the application...")
|
|
16
|
+
print("Status checked")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def create_parser() -> argparse.ArgumentParser:
|
|
20
|
+
parser = argparse.ArgumentParser(
|
|
21
|
+
description="A CLI tool to deploy python lambdas with a single command"
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
subparsers = parser.add_subparsers(dest="command")
|
|
25
|
+
subparsers.required = True
|
|
26
|
+
|
|
27
|
+
parser_deploy = subparsers.add_parser("deploy", help="Deploy the application.")
|
|
28
|
+
parser_deploy.add_argument(
|
|
29
|
+
"file_paths", type=str, help="A comma-separated list of file paths to deploy."
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
subparsers.add_parser("status", help="Check the status of the application.")
|
|
33
|
+
|
|
34
|
+
return parser
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def main() -> None:
|
|
38
|
+
parser = create_parser()
|
|
39
|
+
args = parser.parse_args()
|
|
40
|
+
if args.command == "deploy":
|
|
41
|
+
deploy(args.file_paths)
|
|
42
|
+
elif args.command == "status":
|
|
43
|
+
status()
|
|
44
|
+
else:
|
|
45
|
+
print("Unknown command")
|
|
46
|
+
parser.print_help()
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
if __name__ == "__main__":
|
|
50
|
+
main()
|
|
File without changes
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from unittest.mock import MagicMock, patch
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
from gauge.cli.deploy import DeployHandler
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@pytest.fixture
|
|
12
|
+
def deploy_handler() -> DeployHandler:
|
|
13
|
+
return DeployHandler(["test_file.py"], "test_deploy")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_init() -> None:
|
|
17
|
+
handler = DeployHandler(["file1.py", "file2.py"], "test_deploy")
|
|
18
|
+
assert len(handler.file_paths) == 2
|
|
19
|
+
assert handler.deploy_name == "test_deploy"
|
|
20
|
+
|
|
21
|
+
handler_no_name = DeployHandler(["file1.py"])
|
|
22
|
+
assert len(handler_no_name.file_paths) == 1
|
|
23
|
+
assert len(handler_no_name.deploy_name) == 36 # UUID4 length
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_validate_file_paths(deploy_handler: DeployHandler) -> None:
|
|
27
|
+
with patch("pathlib.Path.exists", return_value=True), patch(
|
|
28
|
+
"pathlib.Path.is_file", return_value=True
|
|
29
|
+
):
|
|
30
|
+
deploy_handler.validate_file_paths() # Should not raise any exception
|
|
31
|
+
|
|
32
|
+
with pytest.raises(SystemExit):
|
|
33
|
+
with patch("pathlib.Path.exists", return_value=False):
|
|
34
|
+
deploy_handler.validate_file_paths()
|
|
35
|
+
|
|
36
|
+
with pytest.raises(SystemExit):
|
|
37
|
+
with patch("pathlib.Path.exists", return_value=True), patch(
|
|
38
|
+
"pathlib.Path.is_file", return_value=False
|
|
39
|
+
):
|
|
40
|
+
deploy_handler.validate_file_paths()
|
|
41
|
+
|
|
42
|
+
with pytest.raises(SystemExit):
|
|
43
|
+
deploy_handler.file_paths = {Path("test_file.txt")}
|
|
44
|
+
deploy_handler.validate_file_paths()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_bundle(deploy_handler: DeployHandler) -> None:
|
|
48
|
+
with patch("zipfile.ZipFile") as mock_zipfile:
|
|
49
|
+
result = deploy_handler.bundle("/tmp")
|
|
50
|
+
assert isinstance(result, Path)
|
|
51
|
+
assert result.name == f"{deploy_handler.deploy_name}.zip"
|
|
52
|
+
mock_zipfile.assert_called_once()
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@patch.object(DeployHandler, "validate_file_paths")
|
|
56
|
+
@patch.object(DeployHandler, "register_deployments")
|
|
57
|
+
@patch.object(DeployHandler, "bundle")
|
|
58
|
+
@patch.object(DeployHandler, "upload")
|
|
59
|
+
def test_deploy(
|
|
60
|
+
mock_upload: MagicMock,
|
|
61
|
+
mock_bundle: MagicMock,
|
|
62
|
+
mock_register: MagicMock,
|
|
63
|
+
mock_validate: MagicMock,
|
|
64
|
+
deploy_handler: DeployHandler,
|
|
65
|
+
) -> None:
|
|
66
|
+
mock_register.return_value = {"test_endpoint": {"function": "test_func"}}
|
|
67
|
+
mock_bundle.return_value = Path("test.zip")
|
|
68
|
+
|
|
69
|
+
deploy_handler.deploy()
|
|
70
|
+
|
|
71
|
+
mock_validate.assert_called_once()
|
|
72
|
+
mock_register.assert_called_once()
|
|
73
|
+
mock_bundle.assert_called_once()
|
|
74
|
+
mock_upload.assert_called_once()
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
from gauge.cli.main import create_parser
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from pytest import CaptureFixture
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_parser_deploy():
|
|
14
|
+
parser = create_parser()
|
|
15
|
+
args = parser.parse_args(["deploy", "test_file.py"])
|
|
16
|
+
assert args.command == "deploy"
|
|
17
|
+
assert args.file_paths == "test_file.py"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_parser_deploy_no_file(capsys: CaptureFixture[str]):
|
|
21
|
+
parser = create_parser()
|
|
22
|
+
with pytest.raises(SystemExit) as exc:
|
|
23
|
+
parser.parse_args(["deploy"])
|
|
24
|
+
assert exc.value.code == 2
|
|
25
|
+
|
|
26
|
+
captured = capsys.readouterr()
|
|
27
|
+
assert "the following arguments are required: file" in captured.err
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_parser_status():
|
|
31
|
+
parser = create_parser()
|
|
32
|
+
args = parser.parse_args(["status"])
|
|
33
|
+
assert args.command == "status"
|
|
File without changes
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Callable
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def endpoint(
|
|
7
|
+
name: str, python_version: str = "3.12", dependencies: list[str] = []
|
|
8
|
+
) -> Callable[..., Any]:
|
|
9
|
+
def endpoint_decorator(
|
|
10
|
+
function: Callable[..., Any],
|
|
11
|
+
) -> Callable[..., Any]:
|
|
12
|
+
def _gauge_register() -> tuple[str, dict[str, str | list[str]]]:
|
|
13
|
+
return name, {
|
|
14
|
+
"function": function.__name__,
|
|
15
|
+
"python_version": python_version,
|
|
16
|
+
"dependencies": dependencies,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function._gauge_register = _gauge_register # pyright: ignore[reportFunctionMemberAccess]
|
|
20
|
+
return function
|
|
21
|
+
|
|
22
|
+
return endpoint_decorator
|
|
File without changes
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from gauge import endpoint
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_default_endpoint_decorator():
|
|
7
|
+
@endpoint(name="name")
|
|
8
|
+
def test_function():
|
|
9
|
+
return "testy"
|
|
10
|
+
|
|
11
|
+
assert test_function() == "testy"
|
|
12
|
+
assert hasattr(test_function, "_gauge_register")
|
|
13
|
+
assert test_function._gauge_register() == (
|
|
14
|
+
"name",
|
|
15
|
+
{
|
|
16
|
+
"dependencies": [],
|
|
17
|
+
"python_version": "3.12",
|
|
18
|
+
"function": "test_function",
|
|
19
|
+
},
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_custom_endpoint_decorator():
|
|
24
|
+
@endpoint(name="name2", dependencies=["fastapi"], python_version="3.13")
|
|
25
|
+
def test_function():
|
|
26
|
+
return "test2"
|
|
27
|
+
|
|
28
|
+
assert test_function() == "test2"
|
|
29
|
+
assert hasattr(test_function, "_gauge_register")
|
|
30
|
+
assert test_function._gauge_register() == (
|
|
31
|
+
"name2",
|
|
32
|
+
{
|
|
33
|
+
"dependencies": ["fastapi"],
|
|
34
|
+
"python_version": "3.13",
|
|
35
|
+
"function": "test_function",
|
|
36
|
+
},
|
|
37
|
+
)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "tine"
|
|
3
|
+
version = "0.0.5"
|
|
4
|
+
authors = [
|
|
5
|
+
{ name="Caelean Barnes", email="caeleanb@gmail.com" },
|
|
6
|
+
{ name="Evan Doyle", email="evanmdoyle@gmail.com" },
|
|
7
|
+
]
|
|
8
|
+
description = "Effortless serverless, in your own cloud"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Programming Language :: Python :: 3",
|
|
13
|
+
"License :: OSI Approved :: MIT License",
|
|
14
|
+
"Operating System :: OS Independent",
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Environment :: Console",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Programming Language :: Python",
|
|
19
|
+
"Programming Language :: Python :: 3.8",
|
|
20
|
+
"Programming Language :: Python :: 3.9",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
25
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
26
|
+
"Topic :: Software Development :: Quality Assurance",
|
|
27
|
+
]
|
|
28
|
+
dependencies = [
|
|
29
|
+
"rich~=13.0",
|
|
30
|
+
"pydantic~=2.0",
|
|
31
|
+
"stdlib-list>=0.10.0; python_version < '3.10'",
|
|
32
|
+
"eval-type-backport>=0.2.0; python_version < '3.10'",
|
|
33
|
+
"boto3~=1.34.145",
|
|
34
|
+
"requests~=2.32.3",
|
|
35
|
+
|
|
36
|
+
]
|
|
37
|
+
keywords = ['python', 'lambda', 'aws', 'serverless', 'fastapi']
|
|
38
|
+
[project.optional-dependencies]
|
|
39
|
+
dev = [
|
|
40
|
+
# Core deps (pinned)
|
|
41
|
+
"pyyaml==6.0.1",
|
|
42
|
+
"pydantic==2.8.2; python_version > '3.7'",
|
|
43
|
+
"rich==13.7.1",
|
|
44
|
+
"fastapi==0.111.1",
|
|
45
|
+
"boto3-stubs-lite==1.34.145",
|
|
46
|
+
"boto3-stubs==1.34.145",
|
|
47
|
+
"tach==0.8.1",
|
|
48
|
+
# Setup
|
|
49
|
+
"pip==24.0",
|
|
50
|
+
# Code Quality
|
|
51
|
+
"pyright==1.1.372",
|
|
52
|
+
"ruff==0.5.2",
|
|
53
|
+
# Build/Release
|
|
54
|
+
"setuptools==69.5.1; python_version > '3.7'",
|
|
55
|
+
"twine==5.1.1; python_version > '3.7'",
|
|
56
|
+
"build==1.2.1; python_version > '3.7'",
|
|
57
|
+
# Tests
|
|
58
|
+
"pytest==8.2.2; python_version > '3.7'",
|
|
59
|
+
"pytest-mock==3.14.0; python_version > '3.7'",
|
|
60
|
+
"coverage==7.6.0; python_version > '3.7'",
|
|
61
|
+
# python version 3.7 pinned dependencies
|
|
62
|
+
"botocore==1.33.13; python_version == '3.7'",
|
|
63
|
+
"boto3-stubs-lite==1.33.13; python_version == '3.7'",
|
|
64
|
+
"boto3-stubs==1.33.13; python_version == '3.7'",
|
|
65
|
+
"pydantic==2.5.3; python_version == '3.7'",
|
|
66
|
+
"setuptools==47.1.0; python_version == '3.7'",
|
|
67
|
+
"twine==4.0.2; python_version == '3.7'",
|
|
68
|
+
"build==1.1.1; python_version == '3.7'",
|
|
69
|
+
"pytest==7.4.4; python_version == '3.7'",
|
|
70
|
+
"pytest-mock==3.11.1; python_version == '3.7'",
|
|
71
|
+
"coverage==7.2.7; python_version == '3.7'",
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
[project.urls]
|
|
76
|
+
Homepage = "https://github.com/gauge-sh/gauge-serverless"
|
|
77
|
+
Issues = "https://github.com/gauge-sh/tach/gauge-serverless"
|
|
78
|
+
|
|
79
|
+
[tool.ruff]
|
|
80
|
+
target-version = "py38"
|
|
81
|
+
exclude = ["**/__pycache__", ".venv", "api/src/transform/template.py"]
|
|
82
|
+
lint.extend-select = ["I", "TCH", "UP"]
|
|
83
|
+
|
|
84
|
+
[tool.ruff.lint.isort]
|
|
85
|
+
required-imports = ["from __future__ import annotations"]
|
|
86
|
+
|
|
87
|
+
[tool.ruff.lint.flake8-type-checking]
|
|
88
|
+
runtime-evaluated-base-classes = [
|
|
89
|
+
"pydantic.BaseModel",
|
|
90
|
+
"pydantic.RootModel",
|
|
91
|
+
]
|
|
92
|
+
runtime-evaluated-decorators = [
|
|
93
|
+
"pydantic.dataclasses.dataclass",
|
|
94
|
+
"dataclasses.dataclass",
|
|
95
|
+
]
|
|
96
|
+
exempt-modules = ["typing", "typing_extensions"]
|
|
97
|
+
|
|
98
|
+
[tool.pyright]
|
|
99
|
+
exclude = ["**/__pycache__", ".venv", "api/src/transform/template.py"]
|
|
100
|
+
strict = ["."]
|
|
101
|
+
pythonVersion = "3.8"
|
|
102
|
+
|
|
103
|
+
[project.scripts]
|
|
104
|
+
gauge = "gauge.cli.main:main"
|
|
105
|
+
|
|
106
|
+
[build-system]
|
|
107
|
+
requires = ["setuptools", "wheel"]
|
|
108
|
+
build-backend = "setuptools.build_meta"
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
[tool.setuptools.packages.find]
|
|
112
|
+
where = ["."]
|
|
113
|
+
include = ["gauge*"]
|
tine-0.0.5/setup.cfg
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: tine
|
|
3
|
+
Version: 0.0.5
|
|
4
|
+
Summary: Effortless serverless, in your own cloud
|
|
5
|
+
Author-email: Caelean Barnes <caeleanb@gmail.com>, Evan Doyle <evanmdoyle@gmail.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/gauge-sh/gauge-serverless
|
|
7
|
+
Project-URL: Issues, https://github.com/gauge-sh/tach/gauge-serverless
|
|
8
|
+
Keywords: python,lambda,aws,serverless,fastapi
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Programming Language :: Python
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
24
|
+
Requires-Python: >=3.8
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
Requires-Dist: rich~=13.0
|
|
27
|
+
Requires-Dist: pydantic~=2.0
|
|
28
|
+
Requires-Dist: stdlib-list>=0.10.0; python_version < "3.10"
|
|
29
|
+
Requires-Dist: eval-type-backport>=0.2.0; python_version < "3.10"
|
|
30
|
+
Requires-Dist: boto3~=1.34.145
|
|
31
|
+
Requires-Dist: requests~=2.32.3
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: pyyaml==6.0.1; extra == "dev"
|
|
34
|
+
Requires-Dist: pydantic==2.8.2; python_version > "3.7" and extra == "dev"
|
|
35
|
+
Requires-Dist: rich==13.7.1; extra == "dev"
|
|
36
|
+
Requires-Dist: fastapi==0.111.1; extra == "dev"
|
|
37
|
+
Requires-Dist: boto3-stubs-lite==1.34.145; extra == "dev"
|
|
38
|
+
Requires-Dist: boto3-stubs==1.34.145; extra == "dev"
|
|
39
|
+
Requires-Dist: tach==0.8.1; extra == "dev"
|
|
40
|
+
Requires-Dist: pip==24.0; extra == "dev"
|
|
41
|
+
Requires-Dist: pyright==1.1.372; extra == "dev"
|
|
42
|
+
Requires-Dist: ruff==0.5.2; extra == "dev"
|
|
43
|
+
Requires-Dist: setuptools==69.5.1; python_version > "3.7" and extra == "dev"
|
|
44
|
+
Requires-Dist: twine==5.1.1; python_version > "3.7" and extra == "dev"
|
|
45
|
+
Requires-Dist: build==1.2.1; python_version > "3.7" and extra == "dev"
|
|
46
|
+
Requires-Dist: pytest==8.2.2; python_version > "3.7" and extra == "dev"
|
|
47
|
+
Requires-Dist: pytest-mock==3.14.0; python_version > "3.7" and extra == "dev"
|
|
48
|
+
Requires-Dist: coverage==7.6.0; python_version > "3.7" and extra == "dev"
|
|
49
|
+
Requires-Dist: botocore==1.33.13; python_version == "3.7" and extra == "dev"
|
|
50
|
+
Requires-Dist: boto3-stubs-lite==1.33.13; python_version == "3.7" and extra == "dev"
|
|
51
|
+
Requires-Dist: boto3-stubs==1.33.13; python_version == "3.7" and extra == "dev"
|
|
52
|
+
Requires-Dist: pydantic==2.5.3; python_version == "3.7" and extra == "dev"
|
|
53
|
+
Requires-Dist: setuptools==47.1.0; python_version == "3.7" and extra == "dev"
|
|
54
|
+
Requires-Dist: twine==4.0.2; python_version == "3.7" and extra == "dev"
|
|
55
|
+
Requires-Dist: build==1.1.1; python_version == "3.7" and extra == "dev"
|
|
56
|
+
Requires-Dist: pytest==7.4.4; python_version == "3.7" and extra == "dev"
|
|
57
|
+
Requires-Dist: pytest-mock==3.11.1; python_version == "3.7" and extra == "dev"
|
|
58
|
+
Requires-Dist: coverage==7.2.7; python_version == "3.7" and extra == "dev"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
pyproject.toml
|
|
2
|
+
gauge/__init__.py
|
|
3
|
+
gauge/cli/__init__.py
|
|
4
|
+
gauge/cli/console.py
|
|
5
|
+
gauge/cli/deploy.py
|
|
6
|
+
gauge/cli/main.py
|
|
7
|
+
gauge/cli/tests/__init__.py
|
|
8
|
+
gauge/cli/tests/sample.py
|
|
9
|
+
gauge/cli/tests/test_deploy.py
|
|
10
|
+
gauge/cli/tests/test_main.py
|
|
11
|
+
gauge/sdk/__init__.py
|
|
12
|
+
gauge/sdk/config.py
|
|
13
|
+
gauge/sdk/main.py
|
|
14
|
+
gauge/sdk/tests/__init__.py
|
|
15
|
+
gauge/sdk/tests/test_sdk.py
|
|
16
|
+
tine.egg-info/PKG-INFO
|
|
17
|
+
tine.egg-info/SOURCES.txt
|
|
18
|
+
tine.egg-info/dependency_links.txt
|
|
19
|
+
tine.egg-info/entry_points.txt
|
|
20
|
+
tine.egg-info/requires.txt
|
|
21
|
+
tine.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
rich~=13.0
|
|
2
|
+
pydantic~=2.0
|
|
3
|
+
boto3~=1.34.145
|
|
4
|
+
requests~=2.32.3
|
|
5
|
+
|
|
6
|
+
[:python_version < "3.10"]
|
|
7
|
+
stdlib-list>=0.10.0
|
|
8
|
+
eval-type-backport>=0.2.0
|
|
9
|
+
|
|
10
|
+
[dev]
|
|
11
|
+
pyyaml==6.0.1
|
|
12
|
+
rich==13.7.1
|
|
13
|
+
fastapi==0.111.1
|
|
14
|
+
boto3-stubs-lite==1.34.145
|
|
15
|
+
boto3-stubs==1.34.145
|
|
16
|
+
tach==0.8.1
|
|
17
|
+
pip==24.0
|
|
18
|
+
pyright==1.1.372
|
|
19
|
+
ruff==0.5.2
|
|
20
|
+
|
|
21
|
+
[dev:python_version == "3.7"]
|
|
22
|
+
botocore==1.33.13
|
|
23
|
+
boto3-stubs-lite==1.33.13
|
|
24
|
+
boto3-stubs==1.33.13
|
|
25
|
+
pydantic==2.5.3
|
|
26
|
+
setuptools==47.1.0
|
|
27
|
+
twine==4.0.2
|
|
28
|
+
build==1.1.1
|
|
29
|
+
pytest==7.4.4
|
|
30
|
+
pytest-mock==3.11.1
|
|
31
|
+
coverage==7.2.7
|
|
32
|
+
|
|
33
|
+
[dev:python_version > "3.7"]
|
|
34
|
+
pydantic==2.8.2
|
|
35
|
+
setuptools==69.5.1
|
|
36
|
+
twine==5.1.1
|
|
37
|
+
build==1.2.1
|
|
38
|
+
pytest==8.2.2
|
|
39
|
+
pytest-mock==3.14.0
|
|
40
|
+
coverage==7.6.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
gauge
|