Skip to content

Notes about the python SDK

Kumar Shivendu edited this page Sep 28, 2023 · 3 revisions

Things that are different about Python SDK compared to other SDKs:

  • Python SDK is designed to be async-first for performance but we expose sync variants of those functions using our sync function (Actually, it also uses an event loop but makes async functions compatible with sync frameworks/workers)
    from supertokens_python.async_to_sync_wrapper import sync
    import asyncio
    
    sync(asyncio.sleep(1)) # Note how you didn't have to use `await` here
    print("Slept for 1 sec")

Publically exposed syncio and asyncio functions have separate directories/modules. Please make sure that they are always consistent with each other.

  • To run tests in CI without dev tag, you can create a branch test-cicd/* and circleci will pick it up.
git checkout -b test-cicd/my-feature
git push --set-upstream origin test-cicd/my-feature
  • It's very likely that you'll face cyclic dependency error. You'll generally have 2 kinds of solutions:

    1. Often, you are mostly just using the import for typing, so in that case, just use:
    from typing import TYPE_CHECKING
    
    if TYPE_CHECKING:
      from foo import Bar
    
    def bar(b: Bar) -> None:
      pass
    1. And sometimes, you might have to slightly change the design (most of the times just the import structure). Watch this video to understand more https://www.youtube.com/watch?v=UnKa_t-M_kM
  • You might also be have to use a type before defining it, in such cases, try this:

    from __future__ import annotations
  • You'd often face pylint/pyright errors. In that case, you can either find a fix or add comment # pylint: disable=rule-name. Here rule name can be found by quickly doing a search. Some examples are no-self-use, redefined-builtin, too-many-public-methods, etc. But please disable them as the last resort. Try always to find a cleaner approach because we have added pylint to ensure best practices.

  • In python SDK, we had to introduce a response mutators to attach session to the response object. They are nothing but list of functions that are given a response object and the functions run in sequence (to alter headers, cookies, etc) just before sending the response to the end user.

  • Mappings for equivalent files in Node vs. Python SDK:

error.ts => exceptions.py
index.ts => __init__.py
types.ts => interfaces.py
  • We often use ABC to implement abstract base classes
from abc import ABC
from typing import Literal

class ContactConfig(ABC):
    STATIC_VARIABLE: str = "value"

    @staticmethod
    def my_static_method(): # Note that self isn't passed
        return "foo"

   @property
   def prop(self):
       return "bar"

    def __init__(self, contact_method: Literal["PHONE", "EMAIL", "EMAIL_OR_PHONE"]):
        self.contact_method = contact_method

    @abc.abstractmethod
    async def method_to_implement_in_child():
        pass

Code style:

Try to follow Google's python style guide. As a devtools company, it's important that our SDKs feel native and smooth for our users (developers)

Recommendations for productivity:

  • To work across multiple versions of python (and python libraries), use virtualenvwrapper. It's a create utility that helps you seamlessly create and enter python virtual environments.
  • Try using PyCharm for editing code. It's refactor feature and speed are unparalleled.
  • Setup alias likes:
alias mc="make check-lint"
alias mf="make format"
alias mfc="mf && mc"

Suggestions:

  • We should try to better document python functions using doc strings (and possibly provide examples for using the function)
def foo():
  """one line description
  
  lengthy description and notes (if any)

  Args:
   param1: ...
   param2: ...

  Returns:
   Lengthy description with example (if possible) 

  Raises:
   IOError: ...
  """
  • We should setup code coverage reports so it's easier to identify lines that are untouched by tests.