Skip to content

Commit

Permalink
refactor: rename Api class to Otf for better clarity
Browse files Browse the repository at this point in the history
fix: correct import paths for User and Otf classes
docs: update example scripts to use Otf class instead of Api

refactor(bookings.py): rename Api to Otf to reflect updated class name
test(test_api.py): update import and usage of Api to Otf to match refactor
  • Loading branch information
NodeJSmith committed Jul 13, 2024
1 parent 264fc8a commit 0ffb313
Show file tree
Hide file tree
Showing 10 changed files with 53 additions and 53 deletions.
4 changes: 2 additions & 2 deletions examples/challenge_tracker_examples.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import asyncio
import os

from otf_api import Api
from otf_api import Otf
from otf_api.models.responses import ChallengeType, EquipmentType

USERNAME = os.getenv("OTF_EMAIL")
PASSWORD = os.getenv("OTF_PASSWORD")


async def main():
otf = await Api.create(USERNAME, PASSWORD)
otf = await Otf.create(USERNAME, PASSWORD)

# challenge tracker content is an overview of the challenges OTF runs
# and your participation in them
Expand Down
4 changes: 2 additions & 2 deletions examples/class_bookings_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import os
from collections import Counter

from otf_api import Api
from otf_api import Otf
from otf_api.models.responses.bookings import BookingStatus
from otf_api.models.responses.classes import ClassType

Expand All @@ -11,7 +11,7 @@


async def main():
otf = await Api.create(USERNAME, PASSWORD)
otf = await Otf.create(USERNAME, PASSWORD)

resp = await otf.get_member_purchases()
print(resp.model_dump_json(indent=4))
Expand Down
4 changes: 2 additions & 2 deletions examples/studio_examples.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import asyncio
import os

from otf_api import Api
from otf_api import Otf

USERNAME = os.getenv("OTF_EMAIL")
PASSWORD = os.getenv("OTF_PASSWORD")


async def main():
otf = await Api.create(USERNAME, PASSWORD)
otf = await Otf.create(USERNAME, PASSWORD)

# if you need to figure out what studios are in an area, you can call `search_studios_by_geo`
# which takes latitude, longitude, distance, page_index, and page_size as arguments
Expand Down
4 changes: 2 additions & 2 deletions examples/workout_examples.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import asyncio
import os

from otf_api import Api
from otf_api import Otf

USERNAME = os.getenv("OTF_EMAIL")
PASSWORD = os.getenv("OTF_PASSWORD")


async def main():
otf = await Api.create(USERNAME, PASSWORD)
otf = await Otf.create(USERNAME, PASSWORD)

resp = await otf.get_member_lifetime_stats()
print(resp.model_dump_json(indent=4))
Expand Down
6 changes: 3 additions & 3 deletions src/otf_api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@

from loguru import logger

from .api import Api
from .models.auth import User
from .api import Otf
from .auth import User

__version__ = "0.3.0"


__all__ = ["Api", "User"]
__all__ = ["Otf", "User"]

logger.remove()
logger.add(sink=sys.stdout, level=os.getenv("OTF_LOG_LEVEL", "INFO"))
10 changes: 5 additions & 5 deletions src/otf_api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from loguru import logger
from yarl import URL

from otf_api.models.auth import User
from otf_api.auth import User
from otf_api.models.responses.body_composition_list import BodyCompositionList
from otf_api.models.responses.book_class import BookClass
from otf_api.models.responses.cancel_booking import CancelBooking
Expand Down Expand Up @@ -57,7 +57,7 @@ class AlreadyBookedError(Exception):
REQUEST_HEADERS = {"Authorization": None, "Content-Type": "application/json", "Accept": "application/json"}


class Api:
class Otf:
"""The main class of the otf-api library. Create an instance using the async method `create`.
Example:
Expand Down Expand Up @@ -127,7 +127,7 @@ async def create(
password: str | None = None,
access_token: str | None = None,
id_token: str | None = None,
) -> "Api":
) -> "Otf":
"""Create a new API instance. Accepts either a username and password or an access token and id token.
Args:
Expand All @@ -146,7 +146,7 @@ async def create(
return self

@classmethod
async def create_with_username(cls, username: str, password: str) -> "Api":
async def create_with_username(cls, username: str, password: str) -> "Otf":
"""Create a new API instance. The username and password are required arguments because even though
we cache the token, they expire so quickly that we usually end up needing to re-authenticate.
Expand All @@ -160,7 +160,7 @@ async def create_with_username(cls, username: str, password: str) -> "Api":
return self

@classmethod
async def create_with_token(cls, access_token: str, id_token: str) -> "Api":
async def create_with_token(cls, access_token: str, id_token: str) -> "Otf":
"""Create a new API instance. The username and password are required arguments because even though
we cache the token, they expire so quickly that we usually end up needing to re-authenticate.
Expand Down
52 changes: 26 additions & 26 deletions src/otf_api/models/auth.py → src/otf_api/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,32 +66,6 @@ class User:
def __init__(self, cognito: Cognito):
self.cognito = cognito

@property
def member_id(self) -> str:
return self.id_claims_data.cognito_username

@property
def member_uuid(self) -> str:
return self.access_claims_data.sub

@property
def access_claims_data(self) -> AccessClaimsData:
return AccessClaimsData(**self.cognito.access_claims)

@property
def id_claims_data(self) -> IdClaimsData:
return IdClaimsData(**self.cognito.id_claims)

def save_to_disk(self) -> None:
self.token_path.parent.mkdir(parents=True, exist_ok=True)
data = {
"username": self.cognito.username,
"id_token": self.cognito.id_token,
"access_token": self.cognito.access_token,
"refresh_token": self.cognito.refresh_token,
}
self.token_path.write_text(json.dumps(data))

@classmethod
def cache_file_exists(cls) -> bool:
return cls.token_path.exists()
Expand Down Expand Up @@ -157,3 +131,29 @@ def refresh_token(self) -> "User":
logger.info("Refreshed tokens")
self.save_to_disk()
return self

@property
def member_id(self) -> str:
return self.id_claims_data.cognito_username

@property
def member_uuid(self) -> str:
return self.access_claims_data.sub

@property
def access_claims_data(self) -> AccessClaimsData:
return AccessClaimsData(**self.cognito.access_claims)

@property
def id_claims_data(self) -> IdClaimsData:
return IdClaimsData(**self.cognito.id_claims)

def save_to_disk(self) -> None:
self.token_path.parent.mkdir(parents=True, exist_ok=True)
data = {
"username": self.cognito.username,
"id_token": self.cognito.id_token,
"access_token": self.cognito.access_token,
"refresh_token": self.cognito.refresh_token,
}
self.token_path.write_text(json.dumps(data))
6 changes: 3 additions & 3 deletions src/otf_api/cli/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
from rich.theme import Theme

import otf_api
from otf_api.auth import User
from otf_api.cli._utilities import is_async_fn, with_cli_exception_handling
from otf_api.models.auth import User

if typing.TYPE_CHECKING:
from otf_api.api import Api
from otf_api import Otf


class OutputType(str, Enum):
Expand Down Expand Up @@ -79,7 +79,7 @@ def __init__(self, *args: typing.Any, **kwargs: typing.Any):
self.console = Console(highlight=False, theme=theme, color_system="auto")

# TODO: clean these up later, just don't want warnings everywhere that these could be None
self.api: Api = None # type: ignore
self.api: Otf = None # type: ignore
self.username: str = None # type: ignore
self.password: str = None # type: ignore
self.output: OutputType = None # type: ignore
Expand Down
12 changes: 6 additions & 6 deletions src/otf_api/cli/bookings.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ async def list_bookings(
bk_status = BookingStatus.get_from_key_insensitive(status.value) if status else None

if not base_app.api:
base_app.api = await otf_api.Api.create(base_app.username, base_app.password)
base_app.api = await otf_api.Otf.create(base_app.username, base_app.password)
bookings = await base_app.api.get_bookings(start_date, end_date, bk_status, limit, exclude_cancelled)

if base_app.output == "json":
Expand All @@ -82,7 +82,7 @@ async def book(class_uuid: str = typer.Option(help="Class UUID to cancel")) -> N
logger.info(f"Booking class {class_uuid}")

if not base_app.api:
base_app.api = await otf_api.Api.create(base_app.username, base_app.password)
base_app.api = await otf_api.Otf.create(base_app.username, base_app.password)
booking = await base_app.api.book_class(class_uuid)

base_app.console.print(booking)
Expand Down Expand Up @@ -115,7 +115,7 @@ async def book_interactive(
class_type_enums = None

if not base_app.api:
base_app.api = await otf_api.Api.create(base_app.username, base_app.password)
base_app.api = await otf_api.Otf.create(base_app.username, base_app.password)

classes = await base_app.api.get_classes(
studio_uuids,
Expand Down Expand Up @@ -152,7 +152,7 @@ async def cancel_interactive() -> None:

with base_app.console.status("Getting bookings...", spinner="arc"):
if not base_app.api:
base_app.api = await otf_api.Api.create(base_app.username, base_app.password)
base_app.api = await otf_api.Otf.create(base_app.username, base_app.password)
bookings = await base_app.api.get_bookings()

result = prompt_select_from_table(
Expand All @@ -177,7 +177,7 @@ async def cancel(booking_uuid: str = typer.Option(help="Booking UUID to cancel")
logger.info(f"Cancelling booking {booking_uuid}")

if not base_app.api:
base_app.api = await otf_api.Api.create(base_app.username, base_app.password)
base_app.api = await otf_api.Otf.create(base_app.username, base_app.password)
booking = await base_app.api.cancel_booking(booking_uuid)

base_app.console.print(booking)
Expand Down Expand Up @@ -211,7 +211,7 @@ async def list_classes(
class_type_enum = ClassType.get_from_key_insensitive(class_type.value) if class_type else None

if not base_app.api:
base_app.api = await otf_api.Api.create(base_app.username, base_app.password)
base_app.api = await otf_api.Otf.create(base_app.username, base_app.password)
classes = await base_app.api.get_classes(
studio_uuids, include_home_studio, start_date, end_date, limit, class_type_enum, exclude_cancelled
)
Expand Down
4 changes: 2 additions & 2 deletions tests/test_api.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import pytest
from otf_api.api import Api
from otf_api.api import Otf


@pytest.mark.asyncio
async def test_api_raises_error_if_no_username_password():
with pytest.raises(TypeError):
await Api.create()
await Otf.create()

0 comments on commit 0ffb313

Please sign in to comment.