Skip to content

Commit

Permalink
add serialization for sessions (#197)
Browse files Browse the repository at this point in the history
  • Loading branch information
Graeme22 authored Jan 12, 2025
1 parent a2d9ce2 commit df9a9f9
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 7 deletions.
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
project = "tastytrade"
copyright = "2024, Graeme Holliday"
author = "Graeme Holliday"
release = "9.6"
release = "9.7"

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "tastytrade"
version = "9.6"
version = "9.7"
description = "An unofficial, sync/async SDK for Tastytrade!"
readme = "README.md"
requires-python = ">=3.9"
Expand Down
2 changes: 1 addition & 1 deletion tastytrade/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
BACKTEST_URL = "https://backtester.vast.tastyworks.com"
CERT_URL = "https://api.cert.tastyworks.com"
VAST_URL = "https://vast.tastyworks.com"
VERSION = "9.6"
VERSION = "9.7"

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
Expand Down
39 changes: 36 additions & 3 deletions tastytrade/session.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
from datetime import date, datetime
from typing import Any, Optional, Union
from typing_extensions import Self

import httpx
import json
from httpx import AsyncClient, Client

from tastytrade import API_URL, CERT_URL
from tastytrade.utils import TastytradeError, TastytradeJsonDataclass, validate_response
Expand Down Expand Up @@ -302,7 +305,7 @@ def __init__(
"Content-Type": "application/json",
}
#: httpx client for sync requests
self.sync_client = httpx.Client(
self.sync_client = Client(
base_url=(CERT_URL if is_test else API_URL), headers=headers
)
if two_factor_authentication is not None:
Expand All @@ -323,9 +326,8 @@ def __init__(
#: A single-use token which can be used to login without a password
self.remember_token = json["data"].get("remember-token")
self.sync_client.headers.update({"Authorization": self.session_token})
self.validate()
#: httpx client for async requests
self.async_client = httpx.AsyncClient(
self.async_client = AsyncClient(
base_url=self.sync_client.base_url, headers=self.sync_client.headers.copy()
)

Expand Down Expand Up @@ -440,3 +442,34 @@ def get_2fa_info(self) -> TwoFactorInfo:
"""
data = self._get("/users/me/two-factor-method")
return TwoFactorInfo(**data)

def serialize(self) -> str:
"""
Serializes the session to a string, useful for storing
a session for later use.
Could be used with pickle, Redis, etc.
"""
attrs = self.__dict__.copy()
del attrs["async_client"]
del attrs["sync_client"]
attrs["user"] = attrs["user"].model_dump()
return json.dumps(attrs)

@classmethod
def deserialize(cls, serialized: str) -> Self:
"""
Create a new Session object from a serialized string.
"""
deserialized = json.loads(serialized)
deserialized["user"] = User(**deserialized["user"])
self = cls.__new__(cls)
self.__dict__ = deserialized
base_url = CERT_URL if self.is_test else API_URL
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": self.session_token,
}
self.sync_client = Client(base_url=base_url, headers=headers)
self.async_client = AsyncClient(base_url=base_url, headers=headers)
return self
6 changes: 6 additions & 0 deletions tests/test_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,9 @@ def test_destroy(credentials):
async def test_destroy_async(credentials):
session = Session(*credentials)
await session.a_destroy()


def test_serialize_deserialize(session):
data = session.serialize()
obj = Session.deserialize(data)
assert set(obj.__dict__.keys()) == set(session.__dict__.keys())
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit df9a9f9

Please sign in to comment.