Module supertokens_python.types

Expand source code
# Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.
#
# This software is licensed under the Apache License, Version 2.0 (the
# "License") as published by the Apache Software Foundation.
#
# You may not use this file except in compliance with the License. You may
# obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import Any, Awaitable, Dict, List, TypeVar, Union, Optional, TYPE_CHECKING
from phonenumbers import format_number, parse  # type: ignore
import phonenumbers  # type: ignore
from typing_extensions import Literal

_T = TypeVar("_T")

if TYPE_CHECKING:
    from supertokens_python.recipe.thirdparty.types import ThirdPartyInfo


class RecipeUserId:
    def __init__(self, recipe_user_id: str):
        self.recipe_user_id = recipe_user_id

    def get_as_string(self) -> str:
        return self.recipe_user_id

    def __eq__(self, other: Any) -> bool:
        if isinstance(other, RecipeUserId):
            return self.recipe_user_id == other.recipe_user_id
        return False


class AccountInfo:
    def __init__(
        self,
        email: Optional[str] = None,
        phone_number: Optional[str] = None,
        third_party: Optional[ThirdPartyInfo] = None,
    ):
        self.email = email
        self.phone_number = phone_number
        self.third_party = third_party

    def to_json(self) -> Dict[str, Any]:
        json_repo: Dict[str, Any] = {}
        if self.email is not None:
            json_repo["email"] = self.email
        if self.phone_number is not None:
            json_repo["phoneNumber"] = self.phone_number
        if self.third_party is not None:
            json_repo["thirdParty"] = {
                "id": self.third_party.id,
                "userId": self.third_party.user_id,
            }
        return json_repo


class LoginMethod(AccountInfo):
    def __init__(
        self,
        recipe_id: Literal["emailpassword", "thirdparty", "passwordless"],
        recipe_user_id: str,
        tenant_ids: List[str],
        email: Union[str, None],
        phone_number: Union[str, None],
        third_party: Union[ThirdPartyInfo, None],
        time_joined: int,
        verified: bool,
    ):
        super().__init__(email, phone_number, third_party)
        self.recipe_id: Literal["emailpassword", "thirdparty", "passwordless"] = (
            recipe_id
        )
        self.recipe_user_id = RecipeUserId(recipe_user_id)
        self.tenant_ids: List[str] = tenant_ids
        self.time_joined = time_joined
        self.verified = verified

    def __eq__(self, other: Any) -> bool:
        if isinstance(other, LoginMethod):
            return (
                self.recipe_id == other.recipe_id
                and self.recipe_user_id == other.recipe_user_id
                and self.tenant_ids == other.tenant_ids
                and self.email == other.email
                and self.phone_number == other.phone_number
                and self.third_party == other.third_party
                and self.time_joined == other.time_joined
                and self.verified == other.verified
            )
        return False

    def has_same_email_as(self, email: Union[str, None]) -> bool:
        if email is None:
            return False
        return (
            self.email is not None
            and self.email.lower().strip() == email.lower().strip()
        )

    def has_same_phone_number_as(self, phone_number: Union[str, None]) -> bool:
        if phone_number is None:
            return False

        cleaned_phone = phone_number.strip()
        try:
            cleaned_phone = format_number(
                parse(phone_number, None), phonenumbers.PhoneNumberFormat.E164
            )
        except Exception:
            pass  # here we just use the stripped version

        return self.phone_number is not None and self.phone_number == cleaned_phone

    def has_same_third_party_info_as(
        self, third_party: Union[ThirdPartyInfo, None]
    ) -> bool:
        if third_party is None:
            return False
        return (
            self.third_party is not None
            and self.third_party.id.strip() == third_party.id.strip()
            and self.third_party.user_id.strip() == third_party.user_id.strip()
        )

    def to_json(self) -> Dict[str, Any]:
        result: Dict[str, Any] = {
            "recipeId": self.recipe_id,
            "recipeUserId": self.recipe_user_id.get_as_string(),
            "tenantIds": self.tenant_ids,
            "timeJoined": self.time_joined,
            "verified": self.verified,
        }
        if self.email is not None:
            result["email"] = self.email
        if self.phone_number is not None:
            result["phoneNumber"] = self.phone_number
        if self.third_party is not None:
            result["thirdParty"] = self.third_party.to_json()
        return result

    @staticmethod
    def from_json(json: Dict[str, Any]) -> "LoginMethod":
        from supertokens_python.recipe.thirdparty.types import ThirdPartyInfo as TPI

        return LoginMethod(
            recipe_id=json["recipeId"],
            recipe_user_id=json["recipeUserId"],
            tenant_ids=json["tenantIds"],
            email=(
                json["email"] if "email" in json and json["email"] is not None else None
            ),
            phone_number=(
                json["phoneNumber"]
                if "phoneNumber" in json and json["phoneNumber"] is not None
                else None
            ),
            third_party=(
                (
                    TPI(json["thirdParty"]["userId"], json["thirdParty"]["id"])
                    if "thirdParty" in json and json["thirdParty"] is not None
                    else None
                )
            ),
            time_joined=json["timeJoined"],
            verified=json["verified"],
        )


class User:
    def __init__(
        self,
        user_id: str,
        is_primary_user: bool,
        tenant_ids: List[str],
        emails: List[str],
        phone_numbers: List[str],
        third_party: List[ThirdPartyInfo],
        login_methods: List[LoginMethod],
        time_joined: int,
    ):
        self.id = user_id
        self.is_primary_user = is_primary_user
        self.tenant_ids = tenant_ids
        self.emails = emails
        self.phone_numbers = phone_numbers
        self.third_party = third_party
        self.login_methods = login_methods
        self.time_joined = time_joined

    def __eq__(self, other: Any) -> bool:
        if isinstance(other, User):
            return (
                self.id == other.id
                and self.is_primary_user == other.is_primary_user
                and self.tenant_ids == other.tenant_ids
                and self.emails == other.emails
                and self.phone_numbers == other.phone_numbers
                and self.third_party == other.third_party
                and self.login_methods == other.login_methods
                and self.time_joined == other.time_joined
            )
        return False

    def to_json(self) -> Dict[str, Any]:
        return {
            "id": self.id,
            "isPrimaryUser": self.is_primary_user,
            "tenantIds": self.tenant_ids,
            "emails": self.emails,
            "phoneNumbers": self.phone_numbers,
            "thirdParty": [tp.to_json() for tp in self.third_party],
            "loginMethods": [lm.to_json() for lm in self.login_methods],
            "timeJoined": self.time_joined,
        }

    @staticmethod
    def from_json(json: Dict[str, Any]) -> "User":
        from supertokens_python.recipe.thirdparty.types import ThirdPartyInfo as TPI

        return User(
            user_id=json["id"],
            is_primary_user=json["isPrimaryUser"],
            tenant_ids=json["tenantIds"],
            emails=json["emails"],
            phone_numbers=json["phoneNumbers"],
            third_party=[TPI.from_json(tp) for tp in json["thirdParty"]],
            login_methods=[LoginMethod.from_json(lm) for lm in json["loginMethods"]],
            time_joined=json["timeJoined"],
        )


class APIResponse(ABC):
    @abstractmethod
    def to_json(self) -> Dict[str, Any]:
        pass


class GeneralErrorResponse(APIResponse):
    def __init__(self, message: str):
        self.status = "GENERAL_ERROR"
        self.message = message

    def to_json(self) -> Dict[str, Any]:
        return {"status": self.status, "message": self.message}


MaybeAwaitable = Union[Awaitable[_T], _T]

Classes

class APIResponse

Helper class that provides a standard way to create an ABC using inheritance.

Expand source code
class APIResponse(ABC):
    @abstractmethod
    def to_json(self) -> Dict[str, Any]:
        pass

Ancestors

  • abc.ABC

Subclasses

Methods

def to_json(self) ‑> Dict[str, Any]
class AccountInfo (email: Optional[str] = None, phone_number: Optional[str] = None, third_party: Optional[ThirdPartyInfo] = None)
Expand source code
class AccountInfo:
    def __init__(
        self,
        email: Optional[str] = None,
        phone_number: Optional[str] = None,
        third_party: Optional[ThirdPartyInfo] = None,
    ):
        self.email = email
        self.phone_number = phone_number
        self.third_party = third_party

    def to_json(self) -> Dict[str, Any]:
        json_repo: Dict[str, Any] = {}
        if self.email is not None:
            json_repo["email"] = self.email
        if self.phone_number is not None:
            json_repo["phoneNumber"] = self.phone_number
        if self.third_party is not None:
            json_repo["thirdParty"] = {
                "id": self.third_party.id,
                "userId": self.third_party.user_id,
            }
        return json_repo

Subclasses

Methods

def to_json(self) ‑> Dict[str, Any]
class GeneralErrorResponse (message: str)

Helper class that provides a standard way to create an ABC using inheritance.

Expand source code
class GeneralErrorResponse(APIResponse):
    def __init__(self, message: str):
        self.status = "GENERAL_ERROR"
        self.message = message

    def to_json(self) -> Dict[str, Any]:
        return {"status": self.status, "message": self.message}

Ancestors

Methods

def to_json(self) ‑> Dict[str, Any]
class LoginMethod (recipe_id: "Literal[('emailpassword', 'thirdparty', 'passwordless')]", recipe_user_id: str, tenant_ids: List[str], email: Union[str, None], phone_number: Union[str, None], third_party: Union[ThirdPartyInfo, None], time_joined: int, verified: bool)
Expand source code
class LoginMethod(AccountInfo):
    def __init__(
        self,
        recipe_id: Literal["emailpassword", "thirdparty", "passwordless"],
        recipe_user_id: str,
        tenant_ids: List[str],
        email: Union[str, None],
        phone_number: Union[str, None],
        third_party: Union[ThirdPartyInfo, None],
        time_joined: int,
        verified: bool,
    ):
        super().__init__(email, phone_number, third_party)
        self.recipe_id: Literal["emailpassword", "thirdparty", "passwordless"] = (
            recipe_id
        )
        self.recipe_user_id = RecipeUserId(recipe_user_id)
        self.tenant_ids: List[str] = tenant_ids
        self.time_joined = time_joined
        self.verified = verified

    def __eq__(self, other: Any) -> bool:
        if isinstance(other, LoginMethod):
            return (
                self.recipe_id == other.recipe_id
                and self.recipe_user_id == other.recipe_user_id
                and self.tenant_ids == other.tenant_ids
                and self.email == other.email
                and self.phone_number == other.phone_number
                and self.third_party == other.third_party
                and self.time_joined == other.time_joined
                and self.verified == other.verified
            )
        return False

    def has_same_email_as(self, email: Union[str, None]) -> bool:
        if email is None:
            return False
        return (
            self.email is not None
            and self.email.lower().strip() == email.lower().strip()
        )

    def has_same_phone_number_as(self, phone_number: Union[str, None]) -> bool:
        if phone_number is None:
            return False

        cleaned_phone = phone_number.strip()
        try:
            cleaned_phone = format_number(
                parse(phone_number, None), phonenumbers.PhoneNumberFormat.E164
            )
        except Exception:
            pass  # here we just use the stripped version

        return self.phone_number is not None and self.phone_number == cleaned_phone

    def has_same_third_party_info_as(
        self, third_party: Union[ThirdPartyInfo, None]
    ) -> bool:
        if third_party is None:
            return False
        return (
            self.third_party is not None
            and self.third_party.id.strip() == third_party.id.strip()
            and self.third_party.user_id.strip() == third_party.user_id.strip()
        )

    def to_json(self) -> Dict[str, Any]:
        result: Dict[str, Any] = {
            "recipeId": self.recipe_id,
            "recipeUserId": self.recipe_user_id.get_as_string(),
            "tenantIds": self.tenant_ids,
            "timeJoined": self.time_joined,
            "verified": self.verified,
        }
        if self.email is not None:
            result["email"] = self.email
        if self.phone_number is not None:
            result["phoneNumber"] = self.phone_number
        if self.third_party is not None:
            result["thirdParty"] = self.third_party.to_json()
        return result

    @staticmethod
    def from_json(json: Dict[str, Any]) -> "LoginMethod":
        from supertokens_python.recipe.thirdparty.types import ThirdPartyInfo as TPI

        return LoginMethod(
            recipe_id=json["recipeId"],
            recipe_user_id=json["recipeUserId"],
            tenant_ids=json["tenantIds"],
            email=(
                json["email"] if "email" in json and json["email"] is not None else None
            ),
            phone_number=(
                json["phoneNumber"]
                if "phoneNumber" in json and json["phoneNumber"] is not None
                else None
            ),
            third_party=(
                (
                    TPI(json["thirdParty"]["userId"], json["thirdParty"]["id"])
                    if "thirdParty" in json and json["thirdParty"] is not None
                    else None
                )
            ),
            time_joined=json["timeJoined"],
            verified=json["verified"],
        )

Ancestors

Static methods

def from_json(json: Dict[str, Any]) ‑> LoginMethod

Methods

def has_same_email_as(self, email: Union[str, None]) ‑> bool
def has_same_phone_number_as(self, phone_number: Union[str, None]) ‑> bool
def has_same_third_party_info_as(self, third_party: Union[ThirdPartyInfo, None])
def to_json(self) ‑> Dict[str, Any]
class RecipeUserId (recipe_user_id: str)
Expand source code
class RecipeUserId:
    def __init__(self, recipe_user_id: str):
        self.recipe_user_id = recipe_user_id

    def get_as_string(self) -> str:
        return self.recipe_user_id

    def __eq__(self, other: Any) -> bool:
        if isinstance(other, RecipeUserId):
            return self.recipe_user_id == other.recipe_user_id
        return False

Methods

def get_as_string(self) ‑> str
class User (user_id: str, is_primary_user: bool, tenant_ids: List[str], emails: List[str], phone_numbers: List[str], third_party: List[ThirdPartyInfo], login_methods: List[LoginMethod], time_joined: int)
Expand source code
class User:
    def __init__(
        self,
        user_id: str,
        is_primary_user: bool,
        tenant_ids: List[str],
        emails: List[str],
        phone_numbers: List[str],
        third_party: List[ThirdPartyInfo],
        login_methods: List[LoginMethod],
        time_joined: int,
    ):
        self.id = user_id
        self.is_primary_user = is_primary_user
        self.tenant_ids = tenant_ids
        self.emails = emails
        self.phone_numbers = phone_numbers
        self.third_party = third_party
        self.login_methods = login_methods
        self.time_joined = time_joined

    def __eq__(self, other: Any) -> bool:
        if isinstance(other, User):
            return (
                self.id == other.id
                and self.is_primary_user == other.is_primary_user
                and self.tenant_ids == other.tenant_ids
                and self.emails == other.emails
                and self.phone_numbers == other.phone_numbers
                and self.third_party == other.third_party
                and self.login_methods == other.login_methods
                and self.time_joined == other.time_joined
            )
        return False

    def to_json(self) -> Dict[str, Any]:
        return {
            "id": self.id,
            "isPrimaryUser": self.is_primary_user,
            "tenantIds": self.tenant_ids,
            "emails": self.emails,
            "phoneNumbers": self.phone_numbers,
            "thirdParty": [tp.to_json() for tp in self.third_party],
            "loginMethods": [lm.to_json() for lm in self.login_methods],
            "timeJoined": self.time_joined,
        }

    @staticmethod
    def from_json(json: Dict[str, Any]) -> "User":
        from supertokens_python.recipe.thirdparty.types import ThirdPartyInfo as TPI

        return User(
            user_id=json["id"],
            is_primary_user=json["isPrimaryUser"],
            tenant_ids=json["tenantIds"],
            emails=json["emails"],
            phone_numbers=json["phoneNumbers"],
            third_party=[TPI.from_json(tp) for tp in json["thirdParty"]],
            login_methods=[LoginMethod.from_json(lm) for lm in json["loginMethods"]],
            time_joined=json["timeJoined"],
        )

Static methods

def from_json(json: Dict[str, Any]) ‑> User

Methods

def to_json(self) ‑> Dict[str, Any]