oauth2fast-fastapi 0.2.2__tar.gz → 0.2.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. {oauth2fast_fastapi-0.2.2/src/oauth2fast_fastapi.egg-info → oauth2fast_fastapi-0.2.4}/PKG-INFO +17 -20
  2. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/README.md +16 -13
  3. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/examples/basic_usage.py +2 -3
  4. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/examples/complete_flow.py +2 -2
  5. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/examples/custom_user.py +3 -3
  6. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/pyproject.toml +10 -3
  7. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/src/oauth2fast_fastapi/__init__.py +2 -1
  8. oauth2fast_fastapi-0.2.4/src/oauth2fast_fastapi/__version__.py +1 -0
  9. oauth2fast_fastapi-0.2.4/src/oauth2fast_fastapi/models/__init__.py +2 -0
  10. oauth2fast_fastapi-0.2.4/src/oauth2fast_fastapi/models/bases.py +18 -0
  11. oauth2fast_fastapi-0.2.4/src/oauth2fast_fastapi/models/mixins.py +53 -0
  12. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/src/oauth2fast_fastapi/models/user_model.py +1 -8
  13. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4/src/oauth2fast_fastapi.egg-info}/PKG-INFO +17 -20
  14. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/src/oauth2fast_fastapi.egg-info/requires.txt +0 -7
  15. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/tests/test_integration.py +3 -2
  16. oauth2fast_fastapi-0.2.2/src/oauth2fast_fastapi/__version__.py +0 -1
  17. oauth2fast_fastapi-0.2.2/src/oauth2fast_fastapi/models/__init__.py +0 -1
  18. oauth2fast_fastapi-0.2.2/src/oauth2fast_fastapi/models/bases.py +0 -10
  19. oauth2fast_fastapi-0.2.2/src/oauth2fast_fastapi/models/mixins.py +0 -32
  20. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/LICENSE +0 -0
  21. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/MANIFEST.in +0 -0
  22. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/docs/env.example +0 -0
  23. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/docs/usage.md +0 -0
  24. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/setup.cfg +0 -0
  25. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/src/oauth2fast_fastapi/database.py +0 -0
  26. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/src/oauth2fast_fastapi/dependencies.py +0 -0
  27. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/src/oauth2fast_fastapi/mail/__init__.py +0 -0
  28. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/src/oauth2fast_fastapi/mail/service.py +0 -0
  29. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/src/oauth2fast_fastapi/mail/templates/verification.html +0 -0
  30. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/src/oauth2fast_fastapi/mail/templates/welcome.html +0 -0
  31. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/src/oauth2fast_fastapi/routers/__init__.py +0 -0
  32. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/src/oauth2fast_fastapi/routers/base_router.py +0 -0
  33. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/src/oauth2fast_fastapi/routers/users_router.py +0 -0
  34. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/src/oauth2fast_fastapi/schemas/__init__.py +0 -0
  35. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/src/oauth2fast_fastapi/schemas/mixins.py +0 -0
  36. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/src/oauth2fast_fastapi/schemas/token_schema.py +0 -0
  37. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/src/oauth2fast_fastapi/schemas/user_schema.py +0 -0
  38. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/src/oauth2fast_fastapi/schemas/verification_schema.py +0 -0
  39. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/src/oauth2fast_fastapi/settings.py +0 -0
  40. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/src/oauth2fast_fastapi/utils/__init__.py +0 -0
  41. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/src/oauth2fast_fastapi/utils/password_utils.py +0 -0
  42. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/src/oauth2fast_fastapi/utils/token_utils.py +0 -0
  43. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/src/oauth2fast_fastapi/utils/verification_utils.py +0 -0
  44. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/src/oauth2fast_fastapi.egg-info/SOURCES.txt +0 -0
  45. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/src/oauth2fast_fastapi.egg-info/dependency_links.txt +0 -0
  46. {oauth2fast_fastapi-0.2.2 → oauth2fast_fastapi-0.2.4}/src/oauth2fast_fastapi.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oauth2fast-fastapi
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: Fast and secure OAuth2 authentication module for FastAPI with email verification
5
5
  Author-email: Angel Daniel Sanchez Castillo <angeldaniel.sanchezcastillo@gmail.com>
6
6
  License: MIT License
@@ -51,12 +51,6 @@ Requires-Dist: argon2-cffi>=25.0.0
51
51
  Requires-Dist: python-multipart>=0.0.6
52
52
  Requires-Dist: log2fast-fastapi>=0.1.0
53
53
  Requires-Dist: sqlmodel>=0.0.16
54
- Provides-Extra: dev
55
- Requires-Dist: pytest>=7.0.0; extra == "dev"
56
- Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
57
- Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
58
- Requires-Dist: httpx>=0.24.0; extra == "dev"
59
- Requires-Dist: mypy>=1.0.0; extra == "dev"
60
54
  Dynamic: license-file
61
55
 
62
56
  # oauth2fast-fastapi
@@ -118,21 +112,24 @@ ALGORITHM=HS256
118
112
  ACCESS_TOKEN_EXPIRE_MINUTES=60
119
113
 
120
114
  # Database Configuration
121
- AUTH_DB__USERNAME=postgres
122
- AUTH_DB__PASSWORD=yourpassword
123
- AUTH_DB__HOSTNAME=localhost
124
- AUTH_DB__NAME=myapp_db
125
- AUTH_DB__PORT=5432
115
+ DB_DEFAULT_CONNECTION=auth
116
+ DB_CONNECTIONS__AUTH__HOST=localhost
117
+ DB_CONNECTIONS__AUTH__PORT=5432
118
+ DB_CONNECTIONS__AUTH__USERNAME=postgres
119
+ DB_CONNECTIONS__AUTH__PASSWORD=yourpassword
120
+ DB_CONNECTIONS__AUTH__DATABASE=myapp_db
126
121
 
127
122
  # Mail Server Configuration
128
- AUTH_MAIL_SERVER__USERNAME=noreply@yourapp.com
129
- AUTH_MAIL_SERVER__PASSWORD=your-smtp-password
130
- AUTH_MAIL_SERVER__SERVER=smtp.gmail.com
131
- AUTH_MAIL_SERVER__PORT=587
132
- AUTH_MAIL_SERVER__FROM_DIRECTION=noreply@yourapp.com
133
- AUTH_MAIL_SERVER__FROM_NAME=Your App
134
- AUTH_MAIL_SERVER__STARTTLS=true
135
- AUTH_MAIL_SERVER__SSL_TLS=false
123
+ MAIL_DEFAULT_ACCOUNT=auth
124
+ MAIL_SMTP_ACCOUNTS__AUTH__HOST=smtp.gmail.com
125
+ MAIL_SMTP_ACCOUNTS__AUTH__PORT=587
126
+ MAIL_SMTP_ACCOUNTS__AUTH__USERNAME="noreply@yourapp.com"
127
+ MAIL_SMTP_ACCOUNTS__AUTH__PASSWORD="your-smtp-password"
128
+ MAIL_SMTP_ACCOUNTS__AUTH__SECURITY=tls
129
+ MAIL_SMTP_ACCOUNTS__AUTH__FROM_EMAIL="noreply@yourapp.com"
130
+ MAIL_SMTP_ACCOUNTS__AUTH__FROM_NAME="Your pp"
131
+ MAIL_SMTP_ACCOUNTS__AUTH__REPLY_TO="reply@yourapp.com"
132
+ MAIL_SMTP_ACCOUNTS__AUTH__TIMEOUT=60
136
133
 
137
134
  # Application Settings
138
135
  PROJECT_NAME=My App
@@ -57,21 +57,24 @@ ALGORITHM=HS256
57
57
  ACCESS_TOKEN_EXPIRE_MINUTES=60
58
58
 
59
59
  # Database Configuration
60
- AUTH_DB__USERNAME=postgres
61
- AUTH_DB__PASSWORD=yourpassword
62
- AUTH_DB__HOSTNAME=localhost
63
- AUTH_DB__NAME=myapp_db
64
- AUTH_DB__PORT=5432
60
+ DB_DEFAULT_CONNECTION=auth
61
+ DB_CONNECTIONS__AUTH__HOST=localhost
62
+ DB_CONNECTIONS__AUTH__PORT=5432
63
+ DB_CONNECTIONS__AUTH__USERNAME=postgres
64
+ DB_CONNECTIONS__AUTH__PASSWORD=yourpassword
65
+ DB_CONNECTIONS__AUTH__DATABASE=myapp_db
65
66
 
66
67
  # Mail Server Configuration
67
- AUTH_MAIL_SERVER__USERNAME=noreply@yourapp.com
68
- AUTH_MAIL_SERVER__PASSWORD=your-smtp-password
69
- AUTH_MAIL_SERVER__SERVER=smtp.gmail.com
70
- AUTH_MAIL_SERVER__PORT=587
71
- AUTH_MAIL_SERVER__FROM_DIRECTION=noreply@yourapp.com
72
- AUTH_MAIL_SERVER__FROM_NAME=Your App
73
- AUTH_MAIL_SERVER__STARTTLS=true
74
- AUTH_MAIL_SERVER__SSL_TLS=false
68
+ MAIL_DEFAULT_ACCOUNT=auth
69
+ MAIL_SMTP_ACCOUNTS__AUTH__HOST=smtp.gmail.com
70
+ MAIL_SMTP_ACCOUNTS__AUTH__PORT=587
71
+ MAIL_SMTP_ACCOUNTS__AUTH__USERNAME="noreply@yourapp.com"
72
+ MAIL_SMTP_ACCOUNTS__AUTH__PASSWORD="your-smtp-password"
73
+ MAIL_SMTP_ACCOUNTS__AUTH__SECURITY=tls
74
+ MAIL_SMTP_ACCOUNTS__AUTH__FROM_EMAIL="noreply@yourapp.com"
75
+ MAIL_SMTP_ACCOUNTS__AUTH__FROM_NAME="Your pp"
76
+ MAIL_SMTP_ACCOUNTS__AUTH__REPLY_TO="reply@yourapp.com"
77
+ MAIL_SMTP_ACCOUNTS__AUTH__TIMEOUT=60
75
78
 
76
79
  # Application Settings
77
80
  PROJECT_NAME=My App
@@ -5,8 +5,7 @@ This example shows how to integrate oauth2fast-fastapi into a FastAPI applicatio
5
5
  """
6
6
 
7
7
  from fastapi import Depends, FastAPI
8
- from oauth2fast_fastapi import User, engine, get_current_user, router
9
- from sqlmodel import SQLModel
8
+ from oauth2fast_fastapi import User, engine, get_current_user, router, AuthModel
10
9
 
11
10
  app = FastAPI(
12
11
  title="OAuth2Fast Example",
@@ -21,7 +20,7 @@ app.include_router(router, prefix="/auth", tags=["Authentication"])
21
20
  async def startup():
22
21
  """Create database tables on startup"""
23
22
  async with engine.begin() as conn:
24
- await conn.run_sync(SQLModel.metadata.create_all)
23
+ await conn.run_sync(AuthModel.metadata.create_all)
25
24
  print("✅ Database tables created")
26
25
  print("📝 Register a user at: POST /auth/users/register")
27
26
  print("🔐 Login at: POST /auth/token")
@@ -12,12 +12,12 @@ This example demonstrates:
12
12
  from fastapi import Depends, FastAPI
13
13
  from oauth2fast_fastapi import (
14
14
  User,
15
+ AuthModel,
15
16
  engine,
16
17
  get_current_user,
17
18
  get_current_verified_user,
18
19
  router,
19
20
  )
20
- from sqlmodel import SQLModel
21
21
 
22
22
  app = FastAPI(
23
23
  title="Complete Auth Flow Example",
@@ -32,7 +32,7 @@ app.include_router(router, prefix="/auth", tags=["Authentication"])
32
32
  async def startup():
33
33
  """Create database tables on startup"""
34
34
  async with engine.begin() as conn:
35
- await conn.run_sync(SQLModel.metadata.create_all)
35
+ await conn.run_sync(AuthModel.metadata.create_all)
36
36
  print("✅ Database ready")
37
37
  print("\n📋 Authentication Flow:")
38
38
  print("1. Register: POST /auth/users/register")
@@ -7,9 +7,9 @@ This example shows how to extend the base User model with custom fields.
7
7
  from datetime import datetime
8
8
 
9
9
  from fastapi import Depends, FastAPI
10
- from oauth2fast_fastapi import engine, get_current_user
10
+ from oauth2fast_fastapi import engine, get_current_user, AuthModel
11
11
  from oauth2fast_fastapi.models.user_model import User as BaseUser
12
- from sqlmodel import Field, SQLModel
12
+ from sqlmodel import Field
13
13
 
14
14
  # Extend the base User model with custom fields
15
15
  class CustomUser(BaseUser, table=True):
@@ -29,7 +29,7 @@ app = FastAPI(title="Custom User Model Example")
29
29
  async def startup():
30
30
  """Create database tables on startup"""
31
31
  async with engine.begin() as conn:
32
- await conn.run_sync(SQLModel.metadata.create_all)
32
+ await conn.run_sync(AuthModel.metadata.create_all)
33
33
  print("✅ Custom user tables created")
34
34
 
35
35
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "oauth2fast-fastapi"
7
- version = "0.2.2"
7
+ version = "0.2.4"
8
8
  description = "Fast and secure OAuth2 authentication module for FastAPI with email verification"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -42,13 +42,20 @@ dependencies = [
42
42
  "sqlmodel>=0.0.16",
43
43
  ]
44
44
 
45
- [project.optional-dependencies]
45
+ [dependency-groups]
46
46
  dev = [
47
+ "black",
48
+ "ruff",
49
+ "mypy>=1.0.0",
50
+ "pre-commit",
51
+ "build",
52
+ "twine",
53
+ ]
54
+ test = [
47
55
  "pytest>=7.0.0",
48
56
  "pytest-asyncio>=0.21.0",
49
57
  "pytest-cov>=4.0.0",
50
58
  "httpx>=0.24.0",
51
- "mypy>=1.0.0",
52
59
  ]
53
60
 
54
61
  [project.urls]
@@ -10,7 +10,7 @@ from .database import (
10
10
  startup_database,
11
11
  )
12
12
  from .dependencies import get_auth_session, get_current_user, get_current_verified_user
13
- from .models.bases import AuthModel
13
+ from .models.bases import AuthModel, BasicAuthModel
14
14
  from .models.user_model import User
15
15
  from .routers.base_router import router
16
16
  from .schemas.user_schema import UserCreate, UserRead
@@ -29,6 +29,7 @@ __all__ = [
29
29
  "get_current_verified_user",
30
30
  # Models and schemas
31
31
  "AuthModel",
32
+ "BasicAuthModel",
32
33
  "User",
33
34
  "UserCreate",
34
35
  "UserRead",
@@ -0,0 +1 @@
1
+ __version__ = "0.2.4"
@@ -0,0 +1,2 @@
1
+ from .bases import AuthModel as AuthModel
2
+ from .bases import BasicAuthModel as BasicAuthModel
@@ -0,0 +1,18 @@
1
+ from sqlmodel import MetaData, SQLModel
2
+
3
+ from .mixins import IdMixin, TimestampMixin
4
+
5
+ metadata = MetaData()
6
+
7
+
8
+ class BasicAuthModel(TimestampMixin, SQLModel):
9
+ """Base model without predefined primary key, but with timestamps."""
10
+
11
+ __abstract__ = True
12
+ metadata = metadata
13
+
14
+
15
+ class AuthModel(IdMixin, BasicAuthModel):
16
+ """Default base model with BigInteger primary key and timestamps."""
17
+
18
+ __abstract__ = True
@@ -0,0 +1,53 @@
1
+ from datetime import UTC, datetime
2
+
3
+ from sqlalchemy import DateTime, func
4
+ from sqlmodel import BigInteger, Field
5
+
6
+
7
+ class IdMixin:
8
+ """Mixin para proveer clave primaria autoincremental tipo BigInteger."""
9
+
10
+ id: int | None = Field(default=None, primary_key=True, index=True, sa_type=BigInteger)
11
+
12
+
13
+ class TimestampMixin:
14
+ """Mixin reutilizable para marcas de tiempo en UTC."""
15
+
16
+ created_at: datetime = Field(
17
+ default_factory=lambda: datetime.now(UTC),
18
+ nullable=False,
19
+ sa_type=DateTime(timezone=True),
20
+ )
21
+ updated_at: datetime = Field(
22
+ default_factory=lambda: datetime.now(UTC),
23
+ nullable=False,
24
+ sa_type=DateTime(timezone=True),
25
+ sa_column_kwargs={"onupdate": func.now()},
26
+ )
27
+
28
+
29
+ class AuditMixin:
30
+ """Mixin para rastrear el usuario que crea y actualiza un registro."""
31
+
32
+ created_by: int | None = Field(
33
+ default=None,
34
+ description="ID of the user who created this record.",
35
+ sa_type=BigInteger,
36
+ )
37
+ updated_by: int | None = Field(
38
+ default=None,
39
+ description="ID of the user who last updated this record.",
40
+ sa_type=BigInteger,
41
+ )
42
+
43
+
44
+ # class Example(TimestampMixin, SQLModel, table=True):
45
+ # """Ejemplo de modelo con timestamps automáticos."""
46
+ # id: int | None = Field(default=None, primary_key=True)
47
+ # name: str
48
+
49
+
50
+ # Opcional: asegurar que updated_at se actualice también del lado de Python
51
+ # @event.listens_for(Example, "before_update", propagate=True)
52
+ # def receive_before_update(mapper, connection, target):
53
+ # target.updated_at = datetime.now(timezone.utc)
@@ -1,8 +1,4 @@
1
- from sqlmodel import (
2
- BigInteger,
3
- Column,
4
- Field,
5
- )
1
+ from sqlmodel import Field
6
2
 
7
3
  from .bases import AuthModel
8
4
 
@@ -12,9 +8,6 @@ from .bases import AuthModel
12
8
  class User(AuthModel, table=True):
13
9
  __tablename__ = "users"
14
10
 
15
- id: int = Field(
16
- default=None, sa_column=Column(BigInteger, index=True, primary_key=True)
17
- )
18
11
  name: str = Field(index=True)
19
12
  email: str = Field(index=True, unique=True)
20
13
  password: str = Field()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oauth2fast-fastapi
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: Fast and secure OAuth2 authentication module for FastAPI with email verification
5
5
  Author-email: Angel Daniel Sanchez Castillo <angeldaniel.sanchezcastillo@gmail.com>
6
6
  License: MIT License
@@ -51,12 +51,6 @@ Requires-Dist: argon2-cffi>=25.0.0
51
51
  Requires-Dist: python-multipart>=0.0.6
52
52
  Requires-Dist: log2fast-fastapi>=0.1.0
53
53
  Requires-Dist: sqlmodel>=0.0.16
54
- Provides-Extra: dev
55
- Requires-Dist: pytest>=7.0.0; extra == "dev"
56
- Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
57
- Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
58
- Requires-Dist: httpx>=0.24.0; extra == "dev"
59
- Requires-Dist: mypy>=1.0.0; extra == "dev"
60
54
  Dynamic: license-file
61
55
 
62
56
  # oauth2fast-fastapi
@@ -118,21 +112,24 @@ ALGORITHM=HS256
118
112
  ACCESS_TOKEN_EXPIRE_MINUTES=60
119
113
 
120
114
  # Database Configuration
121
- AUTH_DB__USERNAME=postgres
122
- AUTH_DB__PASSWORD=yourpassword
123
- AUTH_DB__HOSTNAME=localhost
124
- AUTH_DB__NAME=myapp_db
125
- AUTH_DB__PORT=5432
115
+ DB_DEFAULT_CONNECTION=auth
116
+ DB_CONNECTIONS__AUTH__HOST=localhost
117
+ DB_CONNECTIONS__AUTH__PORT=5432
118
+ DB_CONNECTIONS__AUTH__USERNAME=postgres
119
+ DB_CONNECTIONS__AUTH__PASSWORD=yourpassword
120
+ DB_CONNECTIONS__AUTH__DATABASE=myapp_db
126
121
 
127
122
  # Mail Server Configuration
128
- AUTH_MAIL_SERVER__USERNAME=noreply@yourapp.com
129
- AUTH_MAIL_SERVER__PASSWORD=your-smtp-password
130
- AUTH_MAIL_SERVER__SERVER=smtp.gmail.com
131
- AUTH_MAIL_SERVER__PORT=587
132
- AUTH_MAIL_SERVER__FROM_DIRECTION=noreply@yourapp.com
133
- AUTH_MAIL_SERVER__FROM_NAME=Your App
134
- AUTH_MAIL_SERVER__STARTTLS=true
135
- AUTH_MAIL_SERVER__SSL_TLS=false
123
+ MAIL_DEFAULT_ACCOUNT=auth
124
+ MAIL_SMTP_ACCOUNTS__AUTH__HOST=smtp.gmail.com
125
+ MAIL_SMTP_ACCOUNTS__AUTH__PORT=587
126
+ MAIL_SMTP_ACCOUNTS__AUTH__USERNAME="noreply@yourapp.com"
127
+ MAIL_SMTP_ACCOUNTS__AUTH__PASSWORD="your-smtp-password"
128
+ MAIL_SMTP_ACCOUNTS__AUTH__SECURITY=tls
129
+ MAIL_SMTP_ACCOUNTS__AUTH__FROM_EMAIL="noreply@yourapp.com"
130
+ MAIL_SMTP_ACCOUNTS__AUTH__FROM_NAME="Your pp"
131
+ MAIL_SMTP_ACCOUNTS__AUTH__REPLY_TO="reply@yourapp.com"
132
+ MAIL_SMTP_ACCOUNTS__AUTH__TIMEOUT=60
136
133
 
137
134
  # Application Settings
138
135
  PROJECT_NAME=My App
@@ -6,10 +6,3 @@ argon2-cffi>=25.0.0
6
6
  python-multipart>=0.0.6
7
7
  log2fast-fastapi>=0.1.0
8
8
  sqlmodel>=0.0.16
9
-
10
- [dev]
11
- pytest>=7.0.0
12
- pytest-asyncio>=0.21.0
13
- pytest-cov>=4.0.0
14
- httpx>=0.24.0
15
- mypy>=1.0.0
@@ -60,9 +60,10 @@ async def setup_database():
60
60
 
61
61
  yield
62
62
 
63
- # Cleanup: Drop tables
63
+ # Cleanup: Drop tables with CASCADE to handle dependent tables created by tests
64
64
  async with engine.begin() as conn:
65
- await conn.run_sync(AuthModel.metadata.drop_all)
65
+ for table in reversed(AuthModel.metadata.sorted_tables):
66
+ await conn.execute(pytest.importorskip("sqlalchemy").text(f"DROP TABLE IF EXISTS {table.name} CASCADE"))
66
67
 
67
68
  # Shutdown database connections
68
69
  await shutdown_database()
@@ -1 +0,0 @@
1
- __version__ = "0.2.2"
@@ -1 +0,0 @@
1
- from .bases import AuthModel as AuthModel
@@ -1,10 +0,0 @@
1
- from sqlmodel import MetaData, SQLModel
2
-
3
- from .mixins import TimestampMixin
4
-
5
- metadata = MetaData()
6
-
7
-
8
- class AuthModel(TimestampMixin, SQLModel):
9
- __abstract__ = True
10
- metadata = metadata
@@ -1,32 +0,0 @@
1
- from datetime import UTC, datetime
2
-
3
- from sqlalchemy import DateTime, func
4
- from sqlmodel import Column
5
-
6
-
7
- class TimestampMixin:
8
- """Mixin reutilizable para marcas de tiempo en UTC."""
9
-
10
- created_at = Column(
11
- DateTime(timezone=True),
12
- nullable=False,
13
- default=lambda: datetime.now(UTC),
14
- )
15
- updated_at = Column(
16
- DateTime(timezone=True),
17
- nullable=False,
18
- default=lambda: datetime.now(UTC),
19
- onupdate=func.now(),
20
- )
21
-
22
-
23
- # class Example(TimestampMixin, SQLModel, table=True):
24
- # """Ejemplo de modelo con timestamps automáticos."""
25
- # id: int | None = Field(default=None, primary_key=True)
26
- # name: str
27
-
28
-
29
- # Opcional: asegurar que updated_at se actualice también del lado de Python
30
- # @event.listens_for(Example, "before_update", propagate=True)
31
- # def receive_before_update(mapper, connection, target):
32
- # target.updated_at = datetime.now(timezone.utc)