adding commit
Some checks failed
Nix Tests / nix-test (nix-runner) (push) Failing after 3m41s
Python Tests / python-test (push) Failing after 6m36s

This commit is contained in:
2025-10-22 11:07:55 -05:00
parent c16e970d3f
commit 07fafd8fe7
10 changed files with 56 additions and 128 deletions

3
.gitignore vendored
View File

@@ -154,3 +154,6 @@ out/
# nix # nix
result result
# for local dev might dump cred stuff here
cred/

View File

@@ -1 +1,4 @@
[general_config] [general_config]
backend_base_url = "http://localhost:8080"
backend_user = "test@example.com"
backend_pw = "test"

12
scripts/simple_create_user.sh Executable file
View File

@@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -Eeuox pipefail
banner() {
echo "========================================================"
echo " $*"
echo "========================================================"
}
# utility script for easy testing
uv run taco register --display-name "Display Test" --email "test@example.com" --password "test"

View File

@@ -22,7 +22,6 @@ def parse_args():
trygo_py_cliclient.cli.register.setup_parser(subparsers) trygo_py_cliclient.cli.register.setup_parser(subparsers)
trygo_py_cliclient.cli.login.setup_parser(subparsers) trygo_py_cliclient.cli.login.setup_parser(subparsers)
args = parser.parse_args() args = parser.parse_args()
return args return args
@@ -38,4 +37,6 @@ def main():
_logger.info(f"Got args {args=}") _logger.info(f"Got args {args=}")
_logger.info(f"Loaded config {config=}") _logger.info(f"Loaded config {config=}")
args.func(args) # TODO is there a clean way to hang on to a session for a bit when the cli command has run?
# i guess realistically we don't want that
args.func(config, args)

View File

@@ -2,6 +2,7 @@ import argparse
import logging import logging
import typing import typing
import trygo_py_cliclient.config
import trygo_py_cliclient.client import trygo_py_cliclient.client
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@@ -16,13 +17,13 @@ else:
def setup_parser(subparsers: _SubparserType) -> None: def setup_parser(subparsers: _SubparserType) -> None:
parser = subparsers.add_parser("login") parser = subparsers.add_parser("login")
parser.add_argument("--email", type=str, help="config file location", default="") parser.add_argument("--email", type=str, help="The email to log in with ", default="")
parser.add_argument("--password", type=str, help="config file location", default="") parser.add_argument("--password", type=str, help="Password", default="")
parser.set_defaults(func=run) parser.set_defaults(func=run)
def run(args):
def run(config: trygo_py_cliclient.config.Config, args):
clnt = trygo_py_cliclient.client.TryGoAPIClient("http://localhost:8080/") clnt = trygo_py_cliclient.client.BackendService(config)
response = clnt.login(args.email, args.password) response = clnt.login(args.email, args.password)
_logger.info(response) _logger.info(response)

View File

@@ -23,8 +23,8 @@ def setup_parser(subparsers: _SubparserType) -> None:
parser.add_argument("--password", type=str, help="config file location", default="") parser.add_argument("--password", type=str, help="config file location", default="")
parser.set_defaults(func=run) parser.set_defaults(func=run)
def run(args): def run(args):
clnt = trygo_py_cliclient.client.TryGoAPIClient("http://localhost:8080/") clnt = trygo_py_cliclient.client.TryGoAPIClient("http://localhost:8080/")
response = clnt.register(args.email, args.password, args.display_name) response = clnt.register(args.email, args.password, args.display_name)
_logger.info(response) _logger.info(response)

View File

@@ -2,8 +2,10 @@ import requests
import logging import logging
from typing import Optional, Dict, Any from typing import Optional, Dict, Any
from dataclasses import asdict from dataclasses import asdict
from pathlib import Path
from trygo_py_cliclient.models import User, RegisterRequest, LoginRequest, AuthResponse from trygo_py_cliclient.models import RegisterRequest, LoginRequest, AuthResponse
from trygo_py_cliclient.config import Config
from trygo_py_cliclient.exceptions import ( from trygo_py_cliclient.exceptions import (
TryGoAPIError, TryGoAPIError,
AuthenticationError, AuthenticationError,
@@ -15,17 +17,14 @@ from trygo_py_cliclient.exceptions import (
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
class TryGoAPIClient: class BackendService:
"""HTTP client for TryGo webapp REST API""" def __init__(self, config: Config):
self.base_url = config.general_config.backend_base_url.rstrip("/")
def __init__(self, base_url: str, timeout: int = 30): self.timeout = 30
self.base_url = base_url.rstrip("/")
self.timeout = timeout
self.session = requests.Session() self.session = requests.Session()
self.session.headers.update( self.session.headers.update(
{"Content-Type": "application/json", "User-Agent": "trygo-py-client/0.1.0"} {"Content-Type": "application/json", "User-Agent": "trygo-py-client/0.1.0"}
) )
self._auth_token: Optional[str] = None
def _make_request( def _make_request(
self, method: str, endpoint: str, data: Optional[Dict[str, Any]] = None self, method: str, endpoint: str, data: Optional[Dict[str, Any]] = None
@@ -82,6 +81,7 @@ class TryGoAPIClient:
except ValueError as e: except ValueError as e:
raise TryGoAPIError(f"Invalid JSON response: {e}") raise TryGoAPIError(f"Invalid JSON response: {e}")
# claude really fucked this
except requests.exceptions.Timeout: except requests.exceptions.Timeout:
raise NetworkError("Request timeout") raise NetworkError("Request timeout")
except requests.exceptions.ConnectionError: except requests.exceptions.ConnectionError:
@@ -92,18 +92,6 @@ class TryGoAPIClient:
def register(self, email: str, password: str, display_name: str) -> AuthResponse: def register(self, email: str, password: str, display_name: str) -> AuthResponse:
""" """
Register a new user account Register a new user account
Args:
email: User's email address
password: User's password
display_name: User's display name
Returns:
AuthResponse with registration result
Raises:
ValidationError: If registration data is invalid
TryGoAPIError: If registration fails
""" """
request_data = RegisterRequest( request_data = RegisterRequest(
email=email, password=password, display_name=display_name email=email, password=password, display_name=display_name
@@ -117,42 +105,16 @@ class TryGoAPIClient:
# Parse response and create AuthResponse # Parse response and create AuthResponse
auth_response = AuthResponse( auth_response = AuthResponse(
success=response_data.get("success", False),
message=response_data.get("message", ""), message=response_data.get("message", ""),
token=response_data.get("token"), email=response_data.get("email", ""),
user=None, id=response_data.get("id", ""),
) )
# Parse user data if present
if "user" in response_data and response_data["user"]:
user_data = response_data["user"]
auth_response.user = User(
email=user_data.get("email", ""),
password="", # Never store password in response
display_name=user_data.get("display_name", ""),
id=user_data.get("id"),
)
# Store auth token on successful registration
if auth_response.success and auth_response.token:
self.set_auth_token(auth_response.token)
return auth_response return auth_response
def login(self, email: str, password: str) -> AuthResponse: def login(self, email: str, password: str) -> str:
""" """
Authenticate user and get auth token Authenticate user and get auth token
Args:
email: User's email address
password: User's password
Returns:
AuthResponse with login result and token
Raises:
AuthenticationError: If login credentials are invalid
TryGoAPIError: If login fails
""" """
request_data = LoginRequest(email=email, password=password) request_data = LoginRequest(email=email, password=password)
@@ -162,39 +124,10 @@ class TryGoAPIClient:
_logger.info(response_data) _logger.info(response_data)
# Parse response and create AuthResponse # Parse response and create AuthResponse
auth_response = AuthResponse( token = response_data.get("token", "")
success=response_data.get("success", False), self._store_credential(token)
message=response_data.get("message", ""),
token=response_data.get("token"),
user=None,
)
# Parse user data if present return token
if "user" in response_data and response_data["user"]:
user_data = response_data["user"]
auth_response.user = User(
email=user_data.get("email", ""),
password="", # Never store password in response
display_name=user_data.get("display_name", ""),
id=user_data.get("id"),
)
# Store auth token on successful login
if auth_response.success and auth_response.token:
self.set_auth_token(auth_response.token)
return auth_response
def set_auth_token(self, token: str) -> None:
"""
Set authentication token for subsequent requests
Args:
token: JWT or session token for authentication
"""
self._auth_token = token
self.session.headers["Authorization"] = f"Bearer {token}"
_logger.debug("Authentication token set")
def logout(self) -> None: def logout(self) -> None:
""" """
@@ -205,16 +138,12 @@ class TryGoAPIClient:
_logger.info("Logging out user") _logger.info("Logging out user")
# Try to call logout endpoint if we have a token # Try to call logout endpoint if we have a token
if self._auth_token:
try:
self._make_request("POST", "/auth/logout")
_logger.debug("Server logout successful")
except Exception as e:
_logger.warning(f"Server logout failed (continuing anyway): {e}")
# Clear local auth state
self._auth_token = None
if "Authorization" in self.session.headers:
del self.session.headers["Authorization"]
_logger.debug("Local authentication cleared") _logger.debug("Local authentication cleared")
def _store_credential(self, token: str) -> None:
token_path = Path("cred/token")
token_path.parent.mkdir(parents=True,exist_ok=True)
with token_path.open(mode="w") as tokenf:
tokenf.write(token)

View File

@@ -8,6 +8,10 @@ class GeneralConfig:
log_pattern: str = "%(asctime)s | %(process)d | %(levelname)-7s | %(name)s:%(lineno)d | %(message)s" log_pattern: str = "%(asctime)s | %(process)d | %(levelname)-7s | %(name)s:%(lineno)d | %(message)s"
log_file: Optional[str] = None log_file: Optional[str] = None
log_stream: bool = True log_stream: bool = True
backend_base_url: str = ""
# obviously bad, but for now just keep it
backend_user: str = ""
backend_pw: str = ""
@dataclass(frozen=True) @dataclass(frozen=True)

View File

@@ -42,31 +42,7 @@ def serialize_config(config_dict: dict) -> Config:
Converts a dictionary to a Config object Converts a dictionary to a Config object
Makes assumptions about structure of the config_dict, so validation should happen here too if needed. Makes assumptions about structure of the config_dict, so validation should happen here too if needed.
:param config_dict: dictionary containing config values
:return: Config object
""" """
# generation_config = GenerationConfig(**config_dict["generation_config"])
# general_config_dict = config_dict["general_config"]
# general_config = GeneralConfig(
# root_directory=general_config_dict["root_directory"],
# out_dir_name=general_config_dict["out_dir_name"],
# dots_json_name=general_config_dict["dots_json_name"],
# mega_merged_name=general_config_dict["mega_merged_name"],
# mega_merged_inferenced_name=general_config_dict["mega_merged_inferenced_name"],
# skip_to_stage=general_config_dict["skip_to_stage"],
# measurement_type=MeasurementTypeEnum(general_config_dict["measurement_type"]),
# indexes_json_name=general_config_dict["indexes_json_name"],
# log_pattern=general_config_dict["log_pattern"],
# )
# deepdog_config = DeepdogConfig(**config_dict["deepdog_config"])
# config = Config(
# generation_config=generation_config,
# general_config=general_config,
# deepdog_config=deepdog_config,
# )
config = dacite.from_dict( config = dacite.from_dict(
data_class=Config, data_class=Config,
data=config_dict, data=config_dict,

View File

@@ -33,7 +33,6 @@ class LoginRequest:
class AuthResponse: class AuthResponse:
"""Response from authentication endpoints""" """Response from authentication endpoints"""
success: bool
message: str message: str
user: Optional[User] = None email: Optional[str] = None
token: Optional[str] = None id: Optional[str] = None