Source code for fitrequest.client_base
from typing import Any
import typer
from fitrequest.auth import Auth
from fitrequest.cli_utils import fit_cli_command, is_cli_command
from fitrequest.session import Session
[docs]
class FitRequestBase:
"""
The ``FitRequestBase`` class serves as the common ancestor for all classes that implement `fitrequest` methods.
This class does not generate any methods on its own;
instead, it provides a shared structure and declares attributes and methods that are not automatically generated.
"""
_client_name: str
_version: str
_base_url: str | None
_auth: dict | None
_session: Session
@property
def client_name(self) -> str:
"""Name of the client."""
if hasattr(self, '_session'):
self._client_name = self.session.client_name
return self._client_name
@property
def version(self) -> str:
"""Version of the client. If not provided FitRequest tries to retrieve the version from the python package."""
if hasattr(self, '_session'):
self._version = self.session.version
return self._version
@property
def base_url(self) -> str | None:
"""Default base URL for the generated method."""
if hasattr(self, '_session'):
self._base_url = self.session.base_url
return self._base_url
@property
def auth(self) -> dict | None:
"""Authentication object used by generated methods."""
if hasattr(self, '_session'):
auth = self.session.raw_auth
self._auth = auth.model_dump(exclude_none=True) if isinstance(auth, Auth) else auth
return self._auth
@property
def session(self) -> Session:
"""Provides a shared FitRequest session for all generated methods."""
if not hasattr(self, '_session'):
self._session = Session(
client_name=self.client_name, version=self.version, auth=self.auth, base_url=self.base_url
)
return self._session
# Default username/password __init__ for backward compatibility with fitrequest 0.X.X
def __init__(self, username: str | None = None, password: str | None = None) -> None:
"""Default __init__ method that allows username/password authentication."""
if username or password:
self.session.update(auth={'username': username, 'password': password})
self.session.authenticate()
def __getstate__(self) -> dict:
"""
This method is called during the pickling process and returns the current state of the instance,
excluding the session contained in ``__dict__``.
The session is reconstructed when the instance is loaded from a pickle.
"""
# Update _auth here because its update is lazy:
# it's only updated from the session when the property self.auth is read.
self._auth = self.auth
# Remove session because it's not pickable.
state = self.__dict__.copy()
state.pop('_session', None)
return state
def __setstate__(self, state: dict) -> None:
"""
Invoked during the unpickling process, this method updates `__dict__` with the provided state
and re-authenticates the session, restoring any authentication that was lost during pickling.
"""
self.__dict__.update(state)
self.session.authenticate()
[docs]
@classmethod
def cli_app(cls: Any) -> typer.Typer:
"""
Set up a CLI interface using Typer.
Instantiates the fitrequest client, registers all its methods as commands,
and returns the typer the application.
"""
app = typer.Typer()
client = cls()
for attr_name in dir(client):
if is_cli_command(attr := getattr(client, attr_name)):
app.command()(fit_cli_command(attr))
return app
[docs]
@classmethod
def cli_run(cls: Any) -> None:
"""
Runs the typer application.
"""
cls.cli_app()()