Skip to content

Commit f245390

Browse files
committed
Improve docstrings
1 parent f08370c commit f245390

File tree

2 files changed

+182
-15
lines changed

2 files changed

+182
-15
lines changed

fastapi_users_db_dynamodb/__init__.py

Lines changed: 175 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,29 @@ class DynamoDBBaseUserTable(Model, Generic[ID]):
3434
__tablename__: str = config.get("DATABASE_USERTABLE_NAME")
3535

3636
class Meta:
37+
"""The required `Meta` definitions for PynamoDB.
38+
39+
Args:
40+
table_name (str): The name of the table.
41+
region (str): The AWS region string where the table should be created.
42+
billing_mode (str): The billing mode to use when creating the table. \
43+
Currently only supports `PAY_PER_REQUEST`.
44+
"""
45+
3746
table_name: str = config.get("DATABASE_USERTABLE_NAME")
3847
region: str = config.get("DATABASE_REGION")
3948
billing_mode: str = config.get("DATABASE_BILLING_MODE").value
4049

4150
class EmailIndex(GlobalSecondaryIndex):
51+
"""Enable the `email` attribute to be a Global Secondary Index.
52+
53+
Args:
54+
GlobalSecondaryIndex (_type_): The Global Secondary Index base class.
55+
"""
56+
4257
class Meta:
58+
"""The metadata for the Global Secondary Index."""
59+
4360
index_name: str = "email-index"
4461
projection = AllProjection()
4562

@@ -64,6 +81,12 @@ class Meta:
6481

6582

6683
class DynamoDBBaseUserTableUUID(DynamoDBBaseUserTable[UUID_ID]):
84+
"""A base class representing `User` objects with unique IDs.
85+
86+
Args:
87+
DynamoDBBaseUserTable (_type_): The underlying table object.
88+
"""
89+
6790
if TYPE_CHECKING: # pragma: no cover
6891
id: UUID_ID
6992
else:
@@ -76,26 +99,59 @@ class DynamoDBBaseOAuthAccountTable(Model, Generic[ID]):
7699
__tablename__: str = config.get("DATABASE_OAUTHTABLE_NAME")
77100

78101
class Meta:
102+
"""The required `Meta` definitions for PynamoDB.
103+
104+
Args:
105+
table_name (str): The name of the table.
106+
region (str): The AWS region string where the table should be created.
107+
billing_mode (str): The billing mode to use when creating the table. \
108+
Currently only supports `PAY_PER_REQUEST`.
109+
"""
110+
79111
table_name: str = config.get("DATABASE_OAUTHTABLE_NAME")
80112
region: str = config.get("DATABASE_REGION")
81113
billing_mode: str = config.get("DATABASE_BILLING_MODE").value
82114

83115
class AccountIdIndex(GlobalSecondaryIndex):
116+
"""Enable the `account_id` attribute to be a Global Secondary Index.
117+
118+
Args:
119+
GlobalSecondaryIndex (_type_): The Global Secondary Index base class.
120+
"""
121+
84122
class Meta:
123+
"""The metadata for the Global Secondary Index."""
124+
85125
index_name: str = "account_id-index"
86126
projection = AllProjection()
87127

88128
account_id = UnicodeAttribute(hash_key=True)
89129

90130
class OAuthNameIndex(GlobalSecondaryIndex):
131+
"""Enable the `oauth_name` attribute to be a Global Secondary Index.
132+
133+
Args:
134+
GlobalSecondaryIndex (_type_): The Global Secondary Index base class.
135+
"""
136+
91137
class Meta:
138+
"""The metadata for the Global Secondary Index."""
139+
92140
index_name: str = "oauth_name-index"
93141
projection = AllProjection()
94142

95143
oauth_name = UnicodeAttribute(hash_key=True)
96144

97145
class UserIdIndex(GlobalSecondaryIndex):
146+
"""Enable the `user_id` attribute to be a Global Secondary Index.
147+
148+
Args:
149+
GlobalSecondaryIndex (_type_): The Global Secondary Index base class.
150+
"""
151+
98152
class Meta:
153+
"""The metadata for the Global Secondary Index."""
154+
99155
index_name = "user_id-index"
100156
projection = AllProjection()
101157

@@ -124,6 +180,12 @@ class Meta:
124180

125181

126182
class DynamoDBBaseOAuthAccountTableUUID(DynamoDBBaseOAuthAccountTable[UUID_ID]):
183+
"""A base class representing `OAuthAccount` objects with unique IDs.
184+
185+
Args:
186+
DynamoDBBaseOAuthAccountTable (_type_): The underlying table object.
187+
"""
188+
127189
if TYPE_CHECKING: # pragma: no cover
128190
id: UUID_ID
129191
user_id: UUID_ID
@@ -134,7 +196,9 @@ class DynamoDBBaseOAuthAccountTableUUID(DynamoDBBaseOAuthAccountTable[UUID_ID]):
134196

135197
class DynamoDBUserDatabase(Generic[UP, ID], BaseUserDatabase[UP, ID]):
136198
"""
137-
Database adapter for AWS DynamoDB using aiopynamodb.
199+
Database adapter for AWS DynamoDB using `aiopynamodb`. \
200+
201+
Stores `User` and `OAuth` accounts.
138202
"""
139203

140204
user_table: type[UP]
@@ -145,6 +209,12 @@ def __init__(
145209
user_table: type[UP],
146210
oauth_account_table: type[DynamoDBBaseOAuthAccountTable] | None = None,
147211
):
212+
"""Initialize the database adapter.
213+
214+
Args:
215+
user_table (type[UP]): The underlying table for storing `User` accounts.
216+
oauth_account_table (type[DynamoDBBaseOAuthAccountTable] | None, optional): The underlying table for storing `OAuth` accounts. Defaults to None.
217+
"""
148218
self.user_table = user_table
149219
self.oauth_account_table = oauth_account_table
150220

@@ -153,9 +223,16 @@ async def _hydrate_oauth_accounts(
153223
user: UP,
154224
instant_update: bool = False,
155225
) -> UP:
156-
"""
157-
Populate the `oauth_accounts` list of a user by querying the OAuth table.
158-
This mimics SQLAlchemy's lazy relationship loading.
226+
"""Populate the `oauth_accounts` list of a user by querying the `OAuth` table. \
227+
228+
This mimics *SQLAlchemy*'s lazy relationship loading.
229+
230+
Args:
231+
user (UP): The `User` object that should be refreshed.
232+
instant_update (bool, optional): Whether to use consistent reads. Defaults to False.
233+
234+
Returns:
235+
UP: The refreshed user.
159236
"""
160237
if self.oauth_account_table is None:
161238
return user
@@ -172,7 +249,15 @@ async def _hydrate_oauth_accounts(
172249
return user
173250

174251
async def get(self, id: ID, instant_update: bool = False) -> UP | None:
175-
"""Get a user by id and hydrate oauth_accounts if available."""
252+
"""Get a user by id and hydrate `oauth_accounts` if available.
253+
254+
Args:
255+
id (ID): The id of the user account.
256+
instant_update (bool, optional): Whether to use consistent reads. Defaults to False.
257+
258+
Returns:
259+
UP | None: The `User` object, if found.
260+
"""
176261
await ensure_tables_exist(self.user_table) # type: ignore
177262

178263
try:
@@ -183,7 +268,15 @@ async def get(self, id: ID, instant_update: bool = False) -> UP | None:
183268
return None
184269

185270
async def get_by_email(self, email: str, instant_update: bool = False) -> UP | None:
186-
"""Get a user by email using the email GSI (case-insensitive)."""
271+
"""Get a user by email using the email **Global Secondary Index** (case-insensitive).
272+
273+
Args:
274+
email (str): The email of the user account.
275+
instant_update (bool, optional): Whether to use consistent reads. Defaults to False.
276+
277+
Returns:
278+
UP | None: The `User` object, if found.
279+
"""
187280
await ensure_tables_exist(self.user_table) # type: ignore
188281

189282
email_lower = email.lower()
@@ -202,7 +295,19 @@ async def get_by_oauth_account(
202295
account_id: str,
203296
instant_update: bool = False,
204297
) -> UP | None:
205-
"""Find a user by oauth provider and account_id."""
298+
"""Find a user by oauth provider and `account_id`.
299+
300+
Args:
301+
oauth (str): The name of the `OAuth` provider.
302+
account_id (str): The id of the `OAuth` account.
303+
instant_update (bool, optional): Whether to use consistent reads. Defaults to False.
304+
305+
Raises:
306+
NotImplementedError: If the `OAuth` table was not specified upon initialization.
307+
308+
Returns:
309+
UP | None: The `User` object, if found.
310+
"""
206311
if self.oauth_account_table is None:
207312
raise NotImplementedError()
208313
await ensure_tables_exist(self.user_table, self.oauth_account_table) # type: ignore
@@ -225,7 +330,18 @@ async def get_by_oauth_account(
225330
return None
226331

227332
async def create(self, create_dict: dict[str, Any] | UP) -> UP:
228-
"""Create a new user and return an instance of UP."""
333+
"""Create a new user and return an instance of UP.
334+
335+
Args:
336+
create_dict (dict[str, Any] | UP): A dictionary holding the data of the user account.
337+
338+
Raises:
339+
ValueError: If the user account could not be created for whatever reason.
340+
ValueError: If the user account could not be created because the table did not exist.
341+
342+
Returns:
343+
UP: The newly created `User` object.
344+
"""
229345
await ensure_tables_exist(self.user_table) # type: ignore
230346

231347
if isinstance(create_dict, dict):
@@ -248,7 +364,19 @@ async def create(self, create_dict: dict[str, Any] | UP) -> UP:
248364
return user
249365

250366
async def update(self, user: UP, update_dict: dict[str, Any]) -> UP:
251-
"""Update a user with update_dict and return the updated UP instance."""
367+
"""Update a user with `update_dict` and return the updated UP instance.
368+
369+
Args:
370+
user (UP): The `User` instance to be updated.
371+
update_dict (dict[str, Any]): A dictionary with the changes that should be applied.
372+
373+
Raises:
374+
ValueError: If the user account could not be updated for whatever reason.
375+
ValueError: If the user account could not be updated because the table did not exist.
376+
377+
Returns:
378+
UP: The refreshed `User` object.
379+
"""
252380
await ensure_tables_exist(self.user_table) # type: ignore
253381

254382
try:
@@ -266,7 +394,15 @@ async def update(self, user: UP, update_dict: dict[str, Any]) -> UP:
266394
) from e
267395

268396
async def delete(self, user: UP) -> None:
269-
"""Delete a user."""
397+
"""Delete a user.
398+
399+
Args:
400+
user (UP): The `User` object to be deleted.
401+
402+
Raises:
403+
ValueError: If the user account could not be deleted for whatever reason.
404+
ValueError: If the user account could not be deleted because the table did not exist.
405+
"""
270406
await ensure_tables_exist(self.user_table) # type: ignore
271407

272408
try:
@@ -280,7 +416,20 @@ async def delete(self, user: UP) -> None:
280416
) from e
281417

282418
async def add_oauth_account(self, user: UP, create_dict: dict[str, Any]) -> UP:
283-
"""Add an OAuth account and return the refreshed user (UP)."""
419+
"""Add an `OAuth` account and return the refreshed user (UP).
420+
421+
Args:
422+
user (UP): The `User` object, which the newly created `OAuth` account should be linked to.
423+
create_dict (dict[str, Any]): A dictionary holding the data of the `OAuth` account.
424+
425+
Raises:
426+
NotImplementedError: If the `OAuth` table was not specified upon initialization.
427+
ValueError: If the `OAuth` account could not be created for whatever reason.
428+
ValueError: If the `OAuth` account could not be created because the table did not exist.
429+
430+
Returns:
431+
UP: The refreshed `User` object.
432+
"""
284433
if self.oauth_account_table is None:
285434
raise NotImplementedError()
286435
await ensure_tables_exist(self.user_table, self.oauth_account_table) # type: ignore
@@ -310,7 +459,21 @@ async def update_oauth_account(
310459
oauth_account: OAP, # type: ignore
311460
update_dict: dict[str, Any],
312461
) -> UP:
313-
"""Update an OAuth account and return the refreshed user (UP)."""
462+
"""Update an OAuth account and return the refreshed user (UP).
463+
464+
Args:
465+
user (UP): The `User` object, which the updated `OAuth` account should be linked to.
466+
oauth_account (OAP): The existing `OAuth` account to be updated.
467+
update_dict (dict[str, Any]): A dictionary with the changes that should be applied.
468+
469+
Raises:
470+
NotImplementedError: If the `OAuth` table was not specified upon initialization.
471+
ValueError: If the `OAuth` account could not be updated for whatever reason.
472+
ValueError: If the `OAuth` account could not be updated because the table did not exist.
473+
474+
Returns:
475+
UP: The refreshed `User` object.
476+
"""
314477
if self.oauth_account_table is None:
315478
raise NotImplementedError()
316479
await ensure_tables_exist(self.user_table, self.oauth_account_table) # type: ignore

fastapi_users_db_dynamodb/access_token.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,19 @@ class DynamoDBBaseAccessTokenTableUUID(DynamoDBBaseAccessTokenTable[UUID_ID]):
7676

7777

7878
class DynamoDBAccessTokenDatabase(Generic[AP], AccessTokenDatabase[AP]):
79-
"""Access token database adapter for AWS DynamoDB using `aiopynamodb`."""
79+
"""
80+
Access token database adapter for AWS DynamoDB using `aiopynamodb`. \
81+
82+
Stores `AccessToken`s.
83+
"""
8084

8185
access_token_table: type[AP]
8286

8387
def __init__(self, access_token_table: type[AP]):
8488
"""Initialize the Database adapter.
8589
8690
Args:
87-
access_token_table (type[AP]): The table for storing access tokens.
91+
access_token_table (type[AP]): The underlying table for storing `AccessToken`s.
8892
"""
8993
self.access_token_table = access_token_table
9094

@@ -154,7 +158,7 @@ async def update(self, access_token: AP, update_dict: dict[str, Any]) -> AP:
154158
"""Update an existing access token.
155159
156160
Args:
157-
access_token (AP): The `AccessToken` object to be deleted.
161+
access_token (AP): The `AccessToken` object to be updated.
158162
update_dict (dict[str, Any]): A dictionary with the changes that should be applied.
159163
160164
Raises:

0 commit comments

Comments
 (0)