Spaces:
Sleeping
Sleeping
Praneeth Yerrapragada commited on
Commit ·
878d807
1
Parent(s): a58da97
feat: postgres database schema
Browse filessetup local postgres database and create users, transactions tables
- .env.example +5 -1
- Makefile +1 -1
- README.md +30 -0
- alembic.ini +116 -0
- app/engine/postgresdb.py +29 -0
- app/model/base.py +9 -0
- app/model/transaction.py +16 -0
- app/model/user.py +13 -0
- app/schema/base.py +11 -0
- app/schema/transaction.py +19 -0
- app/schema/user.py +10 -0
- main.py +39 -3
- migration/README +1 -0
- migration/env.py +89 -0
- migration/script.py.mako +26 -0
- migration/versions/cd515c44401d_add_users_transactions_tables.py +55 -0
- poetry.lock +218 -1
- pyproject.toml +5 -0
- tests/test_main.py +9 -0
- tests/test_postgresdb_connection.py +15 -0
.env.example
CHANGED
|
@@ -46,4 +46,8 @@ APP_PORT=8000
|
|
| 46 |
|
| 47 |
# Postgres database configuration
|
| 48 |
POSTGRES_USER=postgres
|
| 49 |
-
POSTGRES_PASSWORD=postgres
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
|
| 47 |
# Postgres database configuration
|
| 48 |
POSTGRES_USER=postgres
|
| 49 |
+
POSTGRES_PASSWORD=postgres
|
| 50 |
+
POSTGRES_DB_NAME=codepath_project_postgres_local
|
| 51 |
+
POSTGRES_DB_HOST=localhost
|
| 52 |
+
POSTGRES_DB_PORT=5432
|
| 53 |
+
SQLALCHEMY_DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_DB_HOST}:${POSTGRES_DB_PORT}/${POSTGRES_DB_NAME}
|
Makefile
CHANGED
|
@@ -5,4 +5,4 @@ build-postgres:
|
|
| 5 |
docker build -t codepath_project_postgres -f Dockerfile.local.postgres .
|
| 6 |
|
| 7 |
run-postgres:
|
| 8 |
-
docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=${POSTGRES_PASSWORD} -e POSTGRES_USER=${POSTGRES_USER} --name
|
|
|
|
| 5 |
docker build -t codepath_project_postgres -f Dockerfile.local.postgres .
|
| 6 |
|
| 7 |
run-postgres:
|
| 8 |
+
docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=${POSTGRES_PASSWORD} -e POSTGRES_USER=${POSTGRES_USER} --name ${POSTGRES_DB_NAME} codepath_project_postgres
|
README.md
CHANGED
|
@@ -69,6 +69,36 @@ The API allows CORS for all origins to simplify development. You can change this
|
|
| 69 |
ENVIRONMENT=prod python main.py
|
| 70 |
```
|
| 71 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
## Using Docker
|
| 73 |
|
| 74 |
1. Build an image for the FastAPI app:
|
|
|
|
| 69 |
ENVIRONMENT=prod python main.py
|
| 70 |
```
|
| 71 |
|
| 72 |
+
## Local Postgres database setup
|
| 73 |
+
|
| 74 |
+
To setup a local postgres database, run:
|
| 75 |
+
|
| 76 |
+
1. Build the docker image:
|
| 77 |
+
|
| 78 |
+
```bash
|
| 79 |
+
make build-postgres
|
| 80 |
+
```
|
| 81 |
+
|
| 82 |
+
2. Start the docker container:
|
| 83 |
+
|
| 84 |
+
```bash
|
| 85 |
+
make run-postgres
|
| 86 |
+
```
|
| 87 |
+
|
| 88 |
+
## Running Migrations
|
| 89 |
+
|
| 90 |
+
To generate new migrations, run:
|
| 91 |
+
|
| 92 |
+
```bash
|
| 93 |
+
alembic revision --autogenerate -m "<your_comment>"
|
| 94 |
+
```
|
| 95 |
+
|
| 96 |
+
To locally verify your changes, run:
|
| 97 |
+
|
| 98 |
+
```bash
|
| 99 |
+
alembic upgrade head
|
| 100 |
+
```
|
| 101 |
+
|
| 102 |
## Using Docker
|
| 103 |
|
| 104 |
1. Build an image for the FastAPI app:
|
alembic.ini
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# A generic, single database configuration.
|
| 2 |
+
|
| 3 |
+
[alembic]
|
| 4 |
+
# path to migration scripts
|
| 5 |
+
script_location = migration
|
| 6 |
+
|
| 7 |
+
# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
|
| 8 |
+
# Uncomment the line below if you want the files to be prepended with date and time
|
| 9 |
+
# see https://alembic.sqlalchemy.org/en/latest/tutorial.html#editing-the-ini-file
|
| 10 |
+
# for all available tokens
|
| 11 |
+
# file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s
|
| 12 |
+
|
| 13 |
+
# sys.path path, will be prepended to sys.path if present.
|
| 14 |
+
# defaults to the current working directory.
|
| 15 |
+
prepend_sys_path = .
|
| 16 |
+
|
| 17 |
+
# timezone to use when rendering the date within the migration file
|
| 18 |
+
# as well as the filename.
|
| 19 |
+
# If specified, requires the python>=3.9 or backports.zoneinfo library.
|
| 20 |
+
# Any required deps can installed by adding `alembic[tz]` to the pip requirements
|
| 21 |
+
# string value is passed to ZoneInfo()
|
| 22 |
+
# leave blank for localtime
|
| 23 |
+
# timezone =
|
| 24 |
+
|
| 25 |
+
# max length of characters to apply to the
|
| 26 |
+
# "slug" field
|
| 27 |
+
# truncate_slug_length = 40
|
| 28 |
+
|
| 29 |
+
# set to 'true' to run the environment during
|
| 30 |
+
# the 'revision' command, regardless of autogenerate
|
| 31 |
+
# revision_environment = false
|
| 32 |
+
|
| 33 |
+
# set to 'true' to allow .pyc and .pyo files without
|
| 34 |
+
# a source .py file to be detected as revisions in the
|
| 35 |
+
# versions/ directory
|
| 36 |
+
# sourceless = false
|
| 37 |
+
|
| 38 |
+
# version location specification; This defaults
|
| 39 |
+
# to migration/versions. When using multiple version
|
| 40 |
+
# directories, initial revisions must be specified with --version-path.
|
| 41 |
+
# The path separator used here should be the separator specified by "version_path_separator" below.
|
| 42 |
+
# version_locations = %(here)s/bar:%(here)s/bat:migration/versions
|
| 43 |
+
|
| 44 |
+
# version path separator; As mentioned above, this is the character used to split
|
| 45 |
+
# version_locations. The default within new alembic.ini files is "os", which uses os.pathsep.
|
| 46 |
+
# If this key is omitted entirely, it falls back to the legacy behavior of splitting on spaces and/or commas.
|
| 47 |
+
# Valid values for version_path_separator are:
|
| 48 |
+
#
|
| 49 |
+
# version_path_separator = :
|
| 50 |
+
# version_path_separator = ;
|
| 51 |
+
# version_path_separator = space
|
| 52 |
+
version_path_separator = os # Use os.pathsep. Default configuration used for new projects.
|
| 53 |
+
|
| 54 |
+
# set to 'true' to search source files recursively
|
| 55 |
+
# in each "version_locations" directory
|
| 56 |
+
# new in Alembic version 1.10
|
| 57 |
+
# recursive_version_locations = false
|
| 58 |
+
|
| 59 |
+
# the output encoding used when revision files
|
| 60 |
+
# are written from script.py.mako
|
| 61 |
+
# output_encoding = utf-8
|
| 62 |
+
|
| 63 |
+
sqlalchemy.url = driver://user:pass@localhost/dbname
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
[post_write_hooks]
|
| 67 |
+
# post_write_hooks defines scripts or Python functions that are run
|
| 68 |
+
# on newly generated revision scripts. See the documentation for further
|
| 69 |
+
# detail and examples
|
| 70 |
+
|
| 71 |
+
# format using "black" - use the console_scripts runner, against the "black" entrypoint
|
| 72 |
+
# hooks = black
|
| 73 |
+
# black.type = console_scripts
|
| 74 |
+
# black.entrypoint = black
|
| 75 |
+
# black.options = -l 79 REVISION_SCRIPT_FILENAME
|
| 76 |
+
|
| 77 |
+
# lint with attempts to fix using "ruff" - use the exec runner, execute a binary
|
| 78 |
+
# hooks = ruff
|
| 79 |
+
# ruff.type = exec
|
| 80 |
+
# ruff.executable = %(here)s/.venv/bin/ruff
|
| 81 |
+
# ruff.options = --fix REVISION_SCRIPT_FILENAME
|
| 82 |
+
|
| 83 |
+
# Logging configuration
|
| 84 |
+
[loggers]
|
| 85 |
+
keys = root,sqlalchemy,alembic
|
| 86 |
+
|
| 87 |
+
[handlers]
|
| 88 |
+
keys = console
|
| 89 |
+
|
| 90 |
+
[formatters]
|
| 91 |
+
keys = generic
|
| 92 |
+
|
| 93 |
+
[logger_root]
|
| 94 |
+
level = WARN
|
| 95 |
+
handlers = console
|
| 96 |
+
qualname =
|
| 97 |
+
|
| 98 |
+
[logger_sqlalchemy]
|
| 99 |
+
level = WARN
|
| 100 |
+
handlers =
|
| 101 |
+
qualname = sqlalchemy.engine
|
| 102 |
+
|
| 103 |
+
[logger_alembic]
|
| 104 |
+
level = INFO
|
| 105 |
+
handlers =
|
| 106 |
+
qualname = alembic
|
| 107 |
+
|
| 108 |
+
[handler_console]
|
| 109 |
+
class = StreamHandler
|
| 110 |
+
args = (sys.stderr,)
|
| 111 |
+
level = NOTSET
|
| 112 |
+
formatter = generic
|
| 113 |
+
|
| 114 |
+
[formatter_generic]
|
| 115 |
+
format = %(levelname)-5.5s [%(name)s] %(message)s
|
| 116 |
+
datefmt = %H:%M:%S
|
app/engine/postgresdb.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import logging
|
| 3 |
+
from sqlalchemy import create_engine
|
| 4 |
+
from sqlalchemy.orm import sessionmaker, declarative_base, Session
|
| 5 |
+
|
| 6 |
+
from dotenv import load_dotenv
|
| 7 |
+
|
| 8 |
+
load_dotenv()
|
| 9 |
+
logger = logging.getLogger(__name__)
|
| 10 |
+
|
| 11 |
+
SQLALCHEMY_DATABASE_URL = os.getenv('SQLALCHEMY_DATABASE_URL')
|
| 12 |
+
assert SQLALCHEMY_DATABASE_URL, f'SQLALCHEMY_DATABASE_URL is not set'
|
| 13 |
+
logger.info(f"SQLALCHEMY_DATABASE_URL: {SQLALCHEMY_DATABASE_URL}")
|
| 14 |
+
|
| 15 |
+
engine = create_engine(SQLALCHEMY_DATABASE_URL)
|
| 16 |
+
|
| 17 |
+
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
| 18 |
+
|
| 19 |
+
Base = declarative_base()
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
# def get_db():
|
| 23 |
+
# session = SessionLocal()
|
| 24 |
+
# logger.info("Postgres Session created successfully!")
|
| 25 |
+
# try:
|
| 26 |
+
# yield session
|
| 27 |
+
# finally:
|
| 28 |
+
# session.close()
|
| 29 |
+
# logger.info("Postgres Session closed successfully!")
|
app/model/base.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from datetime import datetime
|
| 2 |
+
from sqlalchemy import Column, DateTime, Integer
|
| 3 |
+
|
| 4 |
+
from app.engine.postgresdb import Base
|
| 5 |
+
|
| 6 |
+
class BaseModel():
|
| 7 |
+
id = Column(Integer, primary_key=True, index=True)
|
| 8 |
+
created_at = Column(DateTime, default=datetime.now())
|
| 9 |
+
updated_at = Column(DateTime, default=datetime.now(), onupdate=datetime.now())
|
app/model/transaction.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sqlalchemy import Column, DateTime, Float, ForeignKey, Integer, String
|
| 2 |
+
from sqlalchemy.orm import relationship
|
| 3 |
+
|
| 4 |
+
from app.model.base import BaseModel
|
| 5 |
+
from app.engine.postgresdb import Base
|
| 6 |
+
|
| 7 |
+
class Transaction(Base, BaseModel):
|
| 8 |
+
__tablename__ = "transactions"
|
| 9 |
+
transaction_date = Column(DateTime)
|
| 10 |
+
category = Column(String)
|
| 11 |
+
name_description = Column(String)
|
| 12 |
+
amount = Column(Float)
|
| 13 |
+
type = Column(String)
|
| 14 |
+
|
| 15 |
+
user_id = Column(Integer, ForeignKey("users.id"))
|
| 16 |
+
user = relationship("User", back_populates="transactions")
|
app/model/user.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sqlalchemy import Column, String
|
| 2 |
+
from sqlalchemy.orm import relationship
|
| 3 |
+
|
| 4 |
+
from app.model.base import BaseModel
|
| 5 |
+
from app.engine.postgresdb import Base
|
| 6 |
+
|
| 7 |
+
class User(Base, BaseModel):
|
| 8 |
+
__tablename__ = "users"
|
| 9 |
+
|
| 10 |
+
name = Column(String)
|
| 11 |
+
email = Column(String)
|
| 12 |
+
|
| 13 |
+
transactions = relationship("Transaction", back_populates="user")
|
app/schema/base.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from datetime import datetime
|
| 2 |
+
from pydantic import BaseModel
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
class BaseModel(BaseModel):
|
| 6 |
+
id: int
|
| 7 |
+
created_at: datetime
|
| 8 |
+
updated_at: datetime
|
| 9 |
+
|
| 10 |
+
class Config:
|
| 11 |
+
orm_mode = True
|
app/schema/transaction.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from enum import Enum
|
| 2 |
+
from datetime import datetime
|
| 3 |
+
|
| 4 |
+
from app.schema.base import BaseModel
|
| 5 |
+
from app.schema.user import User
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class TransactionType(str, Enum):
|
| 9 |
+
INCOME = "income"
|
| 10 |
+
EXPENSE = "expense"
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
class Transaction(BaseModel):
|
| 14 |
+
transaction_date: datetime
|
| 15 |
+
category: str
|
| 16 |
+
name_description: str
|
| 17 |
+
amount: float
|
| 18 |
+
type: TransactionType
|
| 19 |
+
user: User
|
app/schema/user.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import List
|
| 2 |
+
|
| 3 |
+
from app.schema.base import BaseModel
|
| 4 |
+
from app.schema.transaction import Transaction
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
class User(BaseModel):
|
| 8 |
+
name: str
|
| 9 |
+
email: str
|
| 10 |
+
transactions: "List[Transaction]"
|
main.py
CHANGED
|
@@ -5,16 +5,53 @@ load_dotenv()
|
|
| 5 |
import logging
|
| 6 |
import os
|
| 7 |
import uvicorn
|
| 8 |
-
from
|
|
|
|
| 9 |
from fastapi.middleware.cors import CORSMiddleware
|
| 10 |
from fastapi.responses import RedirectResponse
|
| 11 |
from app.api.routers.chat import chat_router
|
| 12 |
from app.settings import init_settings
|
| 13 |
from app.observability import init_observability
|
| 14 |
from fastapi.staticfiles import StaticFiles
|
|
|
|
|
|
|
| 15 |
|
| 16 |
|
| 17 |
-
app
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
|
| 19 |
init_settings()
|
| 20 |
init_observability()
|
|
@@ -22,7 +59,6 @@ init_observability()
|
|
| 22 |
environment = os.getenv("ENVIRONMENT", "dev") # Default to 'development' if not set
|
| 23 |
|
| 24 |
if environment == "dev":
|
| 25 |
-
logger = logging.getLogger("uvicorn")
|
| 26 |
logger.warning("Running in development mode - allowing CORS for all origins")
|
| 27 |
app.add_middleware(
|
| 28 |
CORSMiddleware,
|
|
|
|
| 5 |
import logging
|
| 6 |
import os
|
| 7 |
import uvicorn
|
| 8 |
+
from contextlib import asynccontextmanager
|
| 9 |
+
from fastapi import FastAPI, Request, Response
|
| 10 |
from fastapi.middleware.cors import CORSMiddleware
|
| 11 |
from fastapi.responses import RedirectResponse
|
| 12 |
from app.api.routers.chat import chat_router
|
| 13 |
from app.settings import init_settings
|
| 14 |
from app.observability import init_observability
|
| 15 |
from fastapi.staticfiles import StaticFiles
|
| 16 |
+
from alembic.config import Config
|
| 17 |
+
from alembic import command
|
| 18 |
|
| 19 |
|
| 20 |
+
from app.engine.postgresdb import engine, Base, SessionLocal
|
| 21 |
+
|
| 22 |
+
logger = logging.getLogger("uvicorn")
|
| 23 |
+
|
| 24 |
+
# Create all tables in the database
|
| 25 |
+
Base.metadata.create_all(bind=engine)
|
| 26 |
+
|
| 27 |
+
def run_migrations():
|
| 28 |
+
alembic_cfg = Config("alembic.ini")
|
| 29 |
+
command.upgrade(alembic_cfg, "head")
|
| 30 |
+
|
| 31 |
+
@asynccontextmanager
|
| 32 |
+
async def lifespan(app_: FastAPI):
|
| 33 |
+
logger.info("Starting up...")
|
| 34 |
+
logger.info("Run 'alembic upgrade head' to apply migrations...")
|
| 35 |
+
run_migrations()
|
| 36 |
+
yield
|
| 37 |
+
logger.info("Shutting down...")
|
| 38 |
+
|
| 39 |
+
app = FastAPI(lifespan=lifespan)
|
| 40 |
+
|
| 41 |
+
@app.middleware("http")
|
| 42 |
+
async def db_session_middleware(request: Request, call_next):
|
| 43 |
+
response = Response("Internal server error", status_code=500)
|
| 44 |
+
try:
|
| 45 |
+
request.state.db = SessionLocal()
|
| 46 |
+
response = await call_next(request)
|
| 47 |
+
finally:
|
| 48 |
+
request.state.db.close()
|
| 49 |
+
return response
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
# Dependency
|
| 53 |
+
def get_db(request: Request):
|
| 54 |
+
return request.state.db
|
| 55 |
|
| 56 |
init_settings()
|
| 57 |
init_observability()
|
|
|
|
| 59 |
environment = os.getenv("ENVIRONMENT", "dev") # Default to 'development' if not set
|
| 60 |
|
| 61 |
if environment == "dev":
|
|
|
|
| 62 |
logger.warning("Running in development mode - allowing CORS for all origins")
|
| 63 |
app.add_middleware(
|
| 64 |
CORSMiddleware,
|
migration/README
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
Generic single-database configuration.
|
migration/env.py
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from logging.config import fileConfig
|
| 3 |
+
|
| 4 |
+
from app.engine.postgresdb import Base
|
| 5 |
+
from sqlalchemy import engine_from_config
|
| 6 |
+
from sqlalchemy import pool
|
| 7 |
+
|
| 8 |
+
from alembic import context
|
| 9 |
+
|
| 10 |
+
from dotenv import load_dotenv
|
| 11 |
+
|
| 12 |
+
load_dotenv()
|
| 13 |
+
|
| 14 |
+
# this is the Alembic Config object, which provides
|
| 15 |
+
# access to the values within the .ini file in use.
|
| 16 |
+
config = context.config
|
| 17 |
+
|
| 18 |
+
config.set_main_option("sqlalchemy.url", os.getenv("SQLALCHEMY_DATABASE_URL"))
|
| 19 |
+
|
| 20 |
+
# Interpret the config file for Python logging.
|
| 21 |
+
# This line sets up loggers basically.
|
| 22 |
+
if config.config_file_name is not None:
|
| 23 |
+
fileConfig(config.config_file_name)
|
| 24 |
+
|
| 25 |
+
# Import all models so they're registered with SQLAlchemy.
|
| 26 |
+
from app.model import *
|
| 27 |
+
|
| 28 |
+
# add your model's MetaData object here
|
| 29 |
+
# for 'autogenerate' support
|
| 30 |
+
# from myapp import mymodel
|
| 31 |
+
# target_metadata = mymodel.Base.metadata
|
| 32 |
+
target_metadata = Base.metadata
|
| 33 |
+
|
| 34 |
+
# other values from the config, defined by the needs of env.py,
|
| 35 |
+
# can be acquired:
|
| 36 |
+
# my_important_option = config.get_main_option("my_important_option")
|
| 37 |
+
# ... etc.
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def run_migrations_offline() -> None:
|
| 41 |
+
"""Run migrations in 'offline' mode.
|
| 42 |
+
|
| 43 |
+
This configures the context with just a URL
|
| 44 |
+
and not an Engine, though an Engine is acceptable
|
| 45 |
+
here as well. By skipping the Engine creation
|
| 46 |
+
we don't even need a DBAPI to be available.
|
| 47 |
+
|
| 48 |
+
Calls to context.execute() here emit the given string to the
|
| 49 |
+
script output.
|
| 50 |
+
|
| 51 |
+
"""
|
| 52 |
+
url = config.get_main_option("sqlalchemy.url")
|
| 53 |
+
context.configure(
|
| 54 |
+
url=url,
|
| 55 |
+
target_metadata=target_metadata,
|
| 56 |
+
literal_binds=True,
|
| 57 |
+
dialect_opts={"paramstyle": "named"},
|
| 58 |
+
)
|
| 59 |
+
|
| 60 |
+
with context.begin_transaction():
|
| 61 |
+
context.run_migrations()
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def run_migrations_online() -> None:
|
| 65 |
+
"""Run migrations in 'online' mode.
|
| 66 |
+
|
| 67 |
+
In this scenario we need to create an Engine
|
| 68 |
+
and associate a connection with the context.
|
| 69 |
+
|
| 70 |
+
"""
|
| 71 |
+
connectable = engine_from_config(
|
| 72 |
+
config.get_section(config.config_ini_section, {}),
|
| 73 |
+
prefix="sqlalchemy.",
|
| 74 |
+
poolclass=pool.NullPool,
|
| 75 |
+
)
|
| 76 |
+
|
| 77 |
+
with connectable.connect() as connection:
|
| 78 |
+
context.configure(
|
| 79 |
+
connection=connection, target_metadata=target_metadata, compare_type=True
|
| 80 |
+
)
|
| 81 |
+
|
| 82 |
+
with context.begin_transaction():
|
| 83 |
+
context.run_migrations()
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
if context.is_offline_mode():
|
| 87 |
+
run_migrations_offline()
|
| 88 |
+
else:
|
| 89 |
+
run_migrations_online()
|
migration/script.py.mako
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""${message}
|
| 2 |
+
|
| 3 |
+
Revision ID: ${up_revision}
|
| 4 |
+
Revises: ${down_revision | comma,n}
|
| 5 |
+
Create Date: ${create_date}
|
| 6 |
+
|
| 7 |
+
"""
|
| 8 |
+
from typing import Sequence, Union
|
| 9 |
+
|
| 10 |
+
from alembic import op
|
| 11 |
+
import sqlalchemy as sa
|
| 12 |
+
${imports if imports else ""}
|
| 13 |
+
|
| 14 |
+
# revision identifiers, used by Alembic.
|
| 15 |
+
revision: str = ${repr(up_revision)}
|
| 16 |
+
down_revision: Union[str, None] = ${repr(down_revision)}
|
| 17 |
+
branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)}
|
| 18 |
+
depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)}
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def upgrade() -> None:
|
| 22 |
+
${upgrades if upgrades else "pass"}
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def downgrade() -> None:
|
| 26 |
+
${downgrades if downgrades else "pass"}
|
migration/versions/cd515c44401d_add_users_transactions_tables.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Add users, transactions tables
|
| 2 |
+
|
| 3 |
+
Revision ID: cd515c44401d
|
| 4 |
+
Revises:
|
| 5 |
+
Create Date: 2024-06-01 01:32:42.500524
|
| 6 |
+
|
| 7 |
+
"""
|
| 8 |
+
from typing import Sequence, Union
|
| 9 |
+
|
| 10 |
+
from alembic import op
|
| 11 |
+
import sqlalchemy as sa
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
# revision identifiers, used by Alembic.
|
| 15 |
+
revision: str = 'cd515c44401d'
|
| 16 |
+
down_revision: Union[str, None] = None
|
| 17 |
+
branch_labels: Union[str, Sequence[str], None] = None
|
| 18 |
+
depends_on: Union[str, Sequence[str], None] = None
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def upgrade() -> None:
|
| 22 |
+
# ### commands auto generated by Alembic - please adjust! ###
|
| 23 |
+
op.create_table('users',
|
| 24 |
+
sa.Column('name', sa.String(), nullable=True),
|
| 25 |
+
sa.Column('email', sa.String(), nullable=True),
|
| 26 |
+
sa.Column('id', sa.Integer(), nullable=False),
|
| 27 |
+
sa.Column('created_at', sa.DateTime(), nullable=True),
|
| 28 |
+
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
| 29 |
+
sa.PrimaryKeyConstraint('id')
|
| 30 |
+
)
|
| 31 |
+
op.create_index(op.f('ix_users_id'), 'users', ['id'], unique=False)
|
| 32 |
+
op.create_table('transactions',
|
| 33 |
+
sa.Column('transaction_date', sa.DateTime(), nullable=True),
|
| 34 |
+
sa.Column('category', sa.String(), nullable=True),
|
| 35 |
+
sa.Column('name_description', sa.String(), nullable=True),
|
| 36 |
+
sa.Column('amount', sa.Float(), nullable=True),
|
| 37 |
+
sa.Column('type', sa.String(), nullable=True),
|
| 38 |
+
sa.Column('user_id', sa.Integer(), nullable=True),
|
| 39 |
+
sa.Column('id', sa.Integer(), nullable=False),
|
| 40 |
+
sa.Column('created_at', sa.DateTime(), nullable=True),
|
| 41 |
+
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
| 42 |
+
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
|
| 43 |
+
sa.PrimaryKeyConstraint('id')
|
| 44 |
+
)
|
| 45 |
+
op.create_index(op.f('ix_transactions_id'), 'transactions', ['id'], unique=False)
|
| 46 |
+
# ### end Alembic commands ###
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
def downgrade() -> None:
|
| 50 |
+
# ### commands auto generated by Alembic - please adjust! ###
|
| 51 |
+
op.drop_index(op.f('ix_transactions_id'), table_name='transactions')
|
| 52 |
+
op.drop_table('transactions')
|
| 53 |
+
op.drop_index(op.f('ix_users_id'), table_name='users')
|
| 54 |
+
op.drop_table('users')
|
| 55 |
+
# ### end Alembic commands ###
|
poetry.lock
CHANGED
|
@@ -123,6 +123,25 @@ files = [
|
|
| 123 |
[package.dependencies]
|
| 124 |
typing-extensions = "*"
|
| 125 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
[[package]]
|
| 127 |
name = "annotated-types"
|
| 128 |
version = "0.7.0"
|
|
@@ -441,6 +460,20 @@ files = [
|
|
| 441 |
{file = "distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed"},
|
| 442 |
]
|
| 443 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 444 |
[[package]]
|
| 445 |
name = "fastapi"
|
| 446 |
version = "0.109.2"
|
|
@@ -925,6 +958,17 @@ files = [
|
|
| 925 |
{file = "inflection-0.5.1.tar.gz", hash = "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417"},
|
| 926 |
]
|
| 927 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 928 |
[[package]]
|
| 929 |
name = "jinja2"
|
| 930 |
version = "3.1.4"
|
|
@@ -1465,6 +1509,25 @@ files = [
|
|
| 1465 |
httpx = ">=0.20.0"
|
| 1466 |
pydantic = ">=1.10"
|
| 1467 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1468 |
[[package]]
|
| 1469 |
name = "markupsafe"
|
| 1470 |
version = "2.1.5"
|
|
@@ -2540,6 +2603,21 @@ urllib3 = {version = ">=1.26.0", markers = "python_version >= \"3.8\" and python
|
|
| 2540 |
[package.extras]
|
| 2541 |
grpc = ["googleapis-common-protos (>=1.53.0)", "grpc-gateway-protoc-gen-openapiv2 (==0.1.0)", "grpcio (>=1.44.0)", "grpcio (>=1.59.0)", "lz4 (>=3.1.3)", "protobuf (>=3.20.0,<3.21.0)"]
|
| 2542 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2543 |
[[package]]
|
| 2544 |
name = "posthog"
|
| 2545 |
version = "3.5.0"
|
|
@@ -2583,6 +2661,87 @@ files = [
|
|
| 2583 |
{file = "protobuf-4.25.3.tar.gz", hash = "sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c"},
|
| 2584 |
]
|
| 2585 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2586 |
[[package]]
|
| 2587 |
name = "pydantic"
|
| 2588 |
version = "2.7.2"
|
|
@@ -2711,6 +2870,64 @@ docs = ["myst_parser", "sphinx", "sphinx_rtd_theme"]
|
|
| 2711 |
full = ["Pillow (>=8.0.0)", "PyCryptodome", "cryptography"]
|
| 2712 |
image = ["Pillow (>=8.0.0)"]
|
| 2713 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2714 |
[[package]]
|
| 2715 |
name = "python-dateutil"
|
| 2716 |
version = "2.9.0.post0"
|
|
@@ -3993,4 +4210,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more
|
|
| 3993 |
[metadata]
|
| 3994 |
lock-version = "2.0"
|
| 3995 |
python-versions = "^3.11,<3.12"
|
| 3996 |
-
content-hash = "
|
|
|
|
| 123 |
[package.dependencies]
|
| 124 |
typing-extensions = "*"
|
| 125 |
|
| 126 |
+
[[package]]
|
| 127 |
+
name = "alembic"
|
| 128 |
+
version = "1.13.1"
|
| 129 |
+
description = "A database migration tool for SQLAlchemy."
|
| 130 |
+
optional = false
|
| 131 |
+
python-versions = ">=3.8"
|
| 132 |
+
files = [
|
| 133 |
+
{file = "alembic-1.13.1-py3-none-any.whl", hash = "sha256:2edcc97bed0bd3272611ce3a98d98279e9c209e7186e43e75bbb1b2bdfdbcc43"},
|
| 134 |
+
{file = "alembic-1.13.1.tar.gz", hash = "sha256:4932c8558bf68f2ee92b9bbcb8218671c627064d5b08939437af6d77dc05e595"},
|
| 135 |
+
]
|
| 136 |
+
|
| 137 |
+
[package.dependencies]
|
| 138 |
+
Mako = "*"
|
| 139 |
+
SQLAlchemy = ">=1.3.0"
|
| 140 |
+
typing-extensions = ">=4"
|
| 141 |
+
|
| 142 |
+
[package.extras]
|
| 143 |
+
tz = ["backports.zoneinfo"]
|
| 144 |
+
|
| 145 |
[[package]]
|
| 146 |
name = "annotated-types"
|
| 147 |
version = "0.7.0"
|
|
|
|
| 460 |
{file = "distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed"},
|
| 461 |
]
|
| 462 |
|
| 463 |
+
[[package]]
|
| 464 |
+
name = "execnet"
|
| 465 |
+
version = "2.1.1"
|
| 466 |
+
description = "execnet: rapid multi-Python deployment"
|
| 467 |
+
optional = false
|
| 468 |
+
python-versions = ">=3.8"
|
| 469 |
+
files = [
|
| 470 |
+
{file = "execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc"},
|
| 471 |
+
{file = "execnet-2.1.1.tar.gz", hash = "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3"},
|
| 472 |
+
]
|
| 473 |
+
|
| 474 |
+
[package.extras]
|
| 475 |
+
testing = ["hatch", "pre-commit", "pytest", "tox"]
|
| 476 |
+
|
| 477 |
[[package]]
|
| 478 |
name = "fastapi"
|
| 479 |
version = "0.109.2"
|
|
|
|
| 958 |
{file = "inflection-0.5.1.tar.gz", hash = "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417"},
|
| 959 |
]
|
| 960 |
|
| 961 |
+
[[package]]
|
| 962 |
+
name = "iniconfig"
|
| 963 |
+
version = "2.0.0"
|
| 964 |
+
description = "brain-dead simple config-ini parsing"
|
| 965 |
+
optional = false
|
| 966 |
+
python-versions = ">=3.7"
|
| 967 |
+
files = [
|
| 968 |
+
{file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
|
| 969 |
+
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
|
| 970 |
+
]
|
| 971 |
+
|
| 972 |
[[package]]
|
| 973 |
name = "jinja2"
|
| 974 |
version = "3.1.4"
|
|
|
|
| 1509 |
httpx = ">=0.20.0"
|
| 1510 |
pydantic = ">=1.10"
|
| 1511 |
|
| 1512 |
+
[[package]]
|
| 1513 |
+
name = "mako"
|
| 1514 |
+
version = "1.3.5"
|
| 1515 |
+
description = "A super-fast templating language that borrows the best ideas from the existing templating languages."
|
| 1516 |
+
optional = false
|
| 1517 |
+
python-versions = ">=3.8"
|
| 1518 |
+
files = [
|
| 1519 |
+
{file = "Mako-1.3.5-py3-none-any.whl", hash = "sha256:260f1dbc3a519453a9c856dedfe4beb4e50bd5a26d96386cb6c80856556bb91a"},
|
| 1520 |
+
{file = "Mako-1.3.5.tar.gz", hash = "sha256:48dbc20568c1d276a2698b36d968fa76161bf127194907ea6fc594fa81f943bc"},
|
| 1521 |
+
]
|
| 1522 |
+
|
| 1523 |
+
[package.dependencies]
|
| 1524 |
+
MarkupSafe = ">=0.9.2"
|
| 1525 |
+
|
| 1526 |
+
[package.extras]
|
| 1527 |
+
babel = ["Babel"]
|
| 1528 |
+
lingua = ["lingua"]
|
| 1529 |
+
testing = ["pytest"]
|
| 1530 |
+
|
| 1531 |
[[package]]
|
| 1532 |
name = "markupsafe"
|
| 1533 |
version = "2.1.5"
|
|
|
|
| 2603 |
[package.extras]
|
| 2604 |
grpc = ["googleapis-common-protos (>=1.53.0)", "grpc-gateway-protoc-gen-openapiv2 (==0.1.0)", "grpcio (>=1.44.0)", "grpcio (>=1.59.0)", "lz4 (>=3.1.3)", "protobuf (>=3.20.0,<3.21.0)"]
|
| 2605 |
|
| 2606 |
+
[[package]]
|
| 2607 |
+
name = "pluggy"
|
| 2608 |
+
version = "1.5.0"
|
| 2609 |
+
description = "plugin and hook calling mechanisms for python"
|
| 2610 |
+
optional = false
|
| 2611 |
+
python-versions = ">=3.8"
|
| 2612 |
+
files = [
|
| 2613 |
+
{file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"},
|
| 2614 |
+
{file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"},
|
| 2615 |
+
]
|
| 2616 |
+
|
| 2617 |
+
[package.extras]
|
| 2618 |
+
dev = ["pre-commit", "tox"]
|
| 2619 |
+
testing = ["pytest", "pytest-benchmark"]
|
| 2620 |
+
|
| 2621 |
[[package]]
|
| 2622 |
name = "posthog"
|
| 2623 |
version = "3.5.0"
|
|
|
|
| 2661 |
{file = "protobuf-4.25.3.tar.gz", hash = "sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c"},
|
| 2662 |
]
|
| 2663 |
|
| 2664 |
+
[[package]]
|
| 2665 |
+
name = "psycopg2-binary"
|
| 2666 |
+
version = "2.9.9"
|
| 2667 |
+
description = "psycopg2 - Python-PostgreSQL Database Adapter"
|
| 2668 |
+
optional = false
|
| 2669 |
+
python-versions = ">=3.7"
|
| 2670 |
+
files = [
|
| 2671 |
+
{file = "psycopg2-binary-2.9.9.tar.gz", hash = "sha256:7f01846810177d829c7692f1f5ada8096762d9172af1b1a28d4ab5b77c923c1c"},
|
| 2672 |
+
{file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c2470da5418b76232f02a2fcd2229537bb2d5a7096674ce61859c3229f2eb202"},
|
| 2673 |
+
{file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c6af2a6d4b7ee9615cbb162b0738f6e1fd1f5c3eda7e5da17861eacf4c717ea7"},
|
| 2674 |
+
{file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:75723c3c0fbbf34350b46a3199eb50638ab22a0228f93fb472ef4d9becc2382b"},
|
| 2675 |
+
{file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83791a65b51ad6ee6cf0845634859d69a038ea9b03d7b26e703f94c7e93dbcf9"},
|
| 2676 |
+
{file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0ef4854e82c09e84cc63084a9e4ccd6d9b154f1dbdd283efb92ecd0b5e2b8c84"},
|
| 2677 |
+
{file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed1184ab8f113e8d660ce49a56390ca181f2981066acc27cf637d5c1e10ce46e"},
|
| 2678 |
+
{file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d2997c458c690ec2bc6b0b7ecbafd02b029b7b4283078d3b32a852a7ce3ddd98"},
|
| 2679 |
+
{file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b58b4710c7f4161b5e9dcbe73bb7c62d65670a87df7bcce9e1faaad43e715245"},
|
| 2680 |
+
{file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0c009475ee389757e6e34611d75f6e4f05f0cf5ebb76c6037508318e1a1e0d7e"},
|
| 2681 |
+
{file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8dbf6d1bc73f1d04ec1734bae3b4fb0ee3cb2a493d35ede9badbeb901fb40f6f"},
|
| 2682 |
+
{file = "psycopg2_binary-2.9.9-cp310-cp310-win32.whl", hash = "sha256:3f78fd71c4f43a13d342be74ebbc0666fe1f555b8837eb113cb7416856c79682"},
|
| 2683 |
+
{file = "psycopg2_binary-2.9.9-cp310-cp310-win_amd64.whl", hash = "sha256:876801744b0dee379e4e3c38b76fc89f88834bb15bf92ee07d94acd06ec890a0"},
|
| 2684 |
+
{file = "psycopg2_binary-2.9.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ee825e70b1a209475622f7f7b776785bd68f34af6e7a46e2e42f27b659b5bc26"},
|
| 2685 |
+
{file = "psycopg2_binary-2.9.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1ea665f8ce695bcc37a90ee52de7a7980be5161375d42a0b6c6abedbf0d81f0f"},
|
| 2686 |
+
{file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:143072318f793f53819048fdfe30c321890af0c3ec7cb1dfc9cc87aa88241de2"},
|
| 2687 |
+
{file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c332c8d69fb64979ebf76613c66b985414927a40f8defa16cf1bc028b7b0a7b0"},
|
| 2688 |
+
{file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7fc5a5acafb7d6ccca13bfa8c90f8c51f13d8fb87d95656d3950f0158d3ce53"},
|
| 2689 |
+
{file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:977646e05232579d2e7b9c59e21dbe5261f403a88417f6a6512e70d3f8a046be"},
|
| 2690 |
+
{file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b6356793b84728d9d50ead16ab43c187673831e9d4019013f1402c41b1db9b27"},
|
| 2691 |
+
{file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bc7bb56d04601d443f24094e9e31ae6deec9ccb23581f75343feebaf30423359"},
|
| 2692 |
+
{file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:77853062a2c45be16fd6b8d6de2a99278ee1d985a7bd8b103e97e41c034006d2"},
|
| 2693 |
+
{file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:78151aa3ec21dccd5cdef6c74c3e73386dcdfaf19bced944169697d7ac7482fc"},
|
| 2694 |
+
{file = "psycopg2_binary-2.9.9-cp311-cp311-win32.whl", hash = "sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d"},
|
| 2695 |
+
{file = "psycopg2_binary-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417"},
|
| 2696 |
+
{file = "psycopg2_binary-2.9.9-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8532fd6e6e2dc57bcb3bc90b079c60de896d2128c5d9d6f24a63875a95a088cf"},
|
| 2697 |
+
{file = "psycopg2_binary-2.9.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0605eaed3eb239e87df0d5e3c6489daae3f7388d455d0c0b4df899519c6a38d"},
|
| 2698 |
+
{file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f8544b092a29a6ddd72f3556a9fcf249ec412e10ad28be6a0c0d948924f2212"},
|
| 2699 |
+
{file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d423c8d8a3c82d08fe8af900ad5b613ce3632a1249fd6a223941d0735fce493"},
|
| 2700 |
+
{file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e5afae772c00980525f6d6ecf7cbca55676296b580c0e6abb407f15f3706996"},
|
| 2701 |
+
{file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e6f98446430fdf41bd36d4faa6cb409f5140c1c2cf58ce0bbdaf16af7d3f119"},
|
| 2702 |
+
{file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c77e3d1862452565875eb31bdb45ac62502feabbd53429fdc39a1cc341d681ba"},
|
| 2703 |
+
{file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cb16c65dcb648d0a43a2521f2f0a2300f40639f6f8c1ecbc662141e4e3e1ee07"},
|
| 2704 |
+
{file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:911dda9c487075abd54e644ccdf5e5c16773470a6a5d3826fda76699410066fb"},
|
| 2705 |
+
{file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:57fede879f08d23c85140a360c6a77709113efd1c993923c59fde17aa27599fe"},
|
| 2706 |
+
{file = "psycopg2_binary-2.9.9-cp312-cp312-win32.whl", hash = "sha256:64cf30263844fa208851ebb13b0732ce674d8ec6a0c86a4e160495d299ba3c93"},
|
| 2707 |
+
{file = "psycopg2_binary-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:81ff62668af011f9a48787564ab7eded4e9fb17a4a6a74af5ffa6a457400d2ab"},
|
| 2708 |
+
{file = "psycopg2_binary-2.9.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2293b001e319ab0d869d660a704942c9e2cce19745262a8aba2115ef41a0a42a"},
|
| 2709 |
+
{file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03ef7df18daf2c4c07e2695e8cfd5ee7f748a1d54d802330985a78d2a5a6dca9"},
|
| 2710 |
+
{file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a602ea5aff39bb9fac6308e9c9d82b9a35c2bf288e184a816002c9fae930b77"},
|
| 2711 |
+
{file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8359bf4791968c5a78c56103702000105501adb557f3cf772b2c207284273984"},
|
| 2712 |
+
{file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:275ff571376626195ab95a746e6a04c7df8ea34638b99fc11160de91f2fef503"},
|
| 2713 |
+
{file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f9b5571d33660d5009a8b3c25dc1db560206e2d2f89d3df1cb32d72c0d117d52"},
|
| 2714 |
+
{file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:420f9bbf47a02616e8554e825208cb947969451978dceb77f95ad09c37791dae"},
|
| 2715 |
+
{file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:4154ad09dac630a0f13f37b583eae260c6aa885d67dfbccb5b02c33f31a6d420"},
|
| 2716 |
+
{file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a148c5d507bb9b4f2030a2025c545fccb0e1ef317393eaba42e7eabd28eb6041"},
|
| 2717 |
+
{file = "psycopg2_binary-2.9.9-cp37-cp37m-win32.whl", hash = "sha256:68fc1f1ba168724771e38bee37d940d2865cb0f562380a1fb1ffb428b75cb692"},
|
| 2718 |
+
{file = "psycopg2_binary-2.9.9-cp37-cp37m-win_amd64.whl", hash = "sha256:281309265596e388ef483250db3640e5f414168c5a67e9c665cafce9492eda2f"},
|
| 2719 |
+
{file = "psycopg2_binary-2.9.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:60989127da422b74a04345096c10d416c2b41bd7bf2a380eb541059e4e999980"},
|
| 2720 |
+
{file = "psycopg2_binary-2.9.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:246b123cc54bb5361588acc54218c8c9fb73068bf227a4a531d8ed56fa3ca7d6"},
|
| 2721 |
+
{file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34eccd14566f8fe14b2b95bb13b11572f7c7d5c36da61caf414d23b91fcc5d94"},
|
| 2722 |
+
{file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18d0ef97766055fec15b5de2c06dd8e7654705ce3e5e5eed3b6651a1d2a9a152"},
|
| 2723 |
+
{file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d3f82c171b4ccd83bbaf35aa05e44e690113bd4f3b7b6cc54d2219b132f3ae55"},
|
| 2724 |
+
{file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ead20f7913a9c1e894aebe47cccf9dc834e1618b7aa96155d2091a626e59c972"},
|
| 2725 |
+
{file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ca49a8119c6cbd77375ae303b0cfd8c11f011abbbd64601167ecca18a87e7cdd"},
|
| 2726 |
+
{file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:323ba25b92454adb36fa425dc5cf6f8f19f78948cbad2e7bc6cdf7b0d7982e59"},
|
| 2727 |
+
{file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:1236ed0952fbd919c100bc839eaa4a39ebc397ed1c08a97fc45fee2a595aa1b3"},
|
| 2728 |
+
{file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:729177eaf0aefca0994ce4cffe96ad3c75e377c7b6f4efa59ebf003b6d398716"},
|
| 2729 |
+
{file = "psycopg2_binary-2.9.9-cp38-cp38-win32.whl", hash = "sha256:804d99b24ad523a1fe18cc707bf741670332f7c7412e9d49cb5eab67e886b9b5"},
|
| 2730 |
+
{file = "psycopg2_binary-2.9.9-cp38-cp38-win_amd64.whl", hash = "sha256:a6cdcc3ede532f4a4b96000b6362099591ab4a3e913d70bcbac2b56c872446f7"},
|
| 2731 |
+
{file = "psycopg2_binary-2.9.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:72dffbd8b4194858d0941062a9766f8297e8868e1dd07a7b36212aaa90f49472"},
|
| 2732 |
+
{file = "psycopg2_binary-2.9.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:30dcc86377618a4c8f3b72418df92e77be4254d8f89f14b8e8f57d6d43603c0f"},
|
| 2733 |
+
{file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31a34c508c003a4347d389a9e6fcc2307cc2150eb516462a7a17512130de109e"},
|
| 2734 |
+
{file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:15208be1c50b99203fe88d15695f22a5bed95ab3f84354c494bcb1d08557df67"},
|
| 2735 |
+
{file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1873aade94b74715be2246321c8650cabf5a0d098a95bab81145ffffa4c13876"},
|
| 2736 |
+
{file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a58c98a7e9c021f357348867f537017057c2ed7f77337fd914d0bedb35dace7"},
|
| 2737 |
+
{file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4686818798f9194d03c9129a4d9a702d9e113a89cb03bffe08c6cf799e053291"},
|
| 2738 |
+
{file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ebdc36bea43063116f0486869652cb2ed7032dbc59fbcb4445c4862b5c1ecf7f"},
|
| 2739 |
+
{file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:ca08decd2697fdea0aea364b370b1249d47336aec935f87b8bbfd7da5b2ee9c1"},
|
| 2740 |
+
{file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ac05fb791acf5e1a3e39402641827780fe44d27e72567a000412c648a85ba860"},
|
| 2741 |
+
{file = "psycopg2_binary-2.9.9-cp39-cp39-win32.whl", hash = "sha256:9dba73be7305b399924709b91682299794887cbbd88e38226ed9f6712eabee90"},
|
| 2742 |
+
{file = "psycopg2_binary-2.9.9-cp39-cp39-win_amd64.whl", hash = "sha256:f7ae5d65ccfbebdfa761585228eb4d0df3a8b15cfb53bd953e713e09fbb12957"},
|
| 2743 |
+
]
|
| 2744 |
+
|
| 2745 |
[[package]]
|
| 2746 |
name = "pydantic"
|
| 2747 |
version = "2.7.2"
|
|
|
|
| 2870 |
full = ["Pillow (>=8.0.0)", "PyCryptodome", "cryptography"]
|
| 2871 |
image = ["Pillow (>=8.0.0)"]
|
| 2872 |
|
| 2873 |
+
[[package]]
|
| 2874 |
+
name = "pytest"
|
| 2875 |
+
version = "8.2.1"
|
| 2876 |
+
description = "pytest: simple powerful testing with Python"
|
| 2877 |
+
optional = false
|
| 2878 |
+
python-versions = ">=3.8"
|
| 2879 |
+
files = [
|
| 2880 |
+
{file = "pytest-8.2.1-py3-none-any.whl", hash = "sha256:faccc5d332b8c3719f40283d0d44aa5cf101cec36f88cde9ed8f2bc0538612b1"},
|
| 2881 |
+
{file = "pytest-8.2.1.tar.gz", hash = "sha256:5046e5b46d8e4cac199c373041f26be56fdb81eb4e67dc11d4e10811fc3408fd"},
|
| 2882 |
+
]
|
| 2883 |
+
|
| 2884 |
+
[package.dependencies]
|
| 2885 |
+
colorama = {version = "*", markers = "sys_platform == \"win32\""}
|
| 2886 |
+
iniconfig = "*"
|
| 2887 |
+
packaging = "*"
|
| 2888 |
+
pluggy = ">=1.5,<2.0"
|
| 2889 |
+
|
| 2890 |
+
[package.extras]
|
| 2891 |
+
dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
|
| 2892 |
+
|
| 2893 |
+
[[package]]
|
| 2894 |
+
name = "pytest-asyncio"
|
| 2895 |
+
version = "0.23.7"
|
| 2896 |
+
description = "Pytest support for asyncio"
|
| 2897 |
+
optional = false
|
| 2898 |
+
python-versions = ">=3.8"
|
| 2899 |
+
files = [
|
| 2900 |
+
{file = "pytest_asyncio-0.23.7-py3-none-any.whl", hash = "sha256:009b48127fbe44518a547bddd25611551b0e43ccdbf1e67d12479f569832c20b"},
|
| 2901 |
+
{file = "pytest_asyncio-0.23.7.tar.gz", hash = "sha256:5f5c72948f4c49e7db4f29f2521d4031f1c27f86e57b046126654083d4770268"},
|
| 2902 |
+
]
|
| 2903 |
+
|
| 2904 |
+
[package.dependencies]
|
| 2905 |
+
pytest = ">=7.0.0,<9"
|
| 2906 |
+
|
| 2907 |
+
[package.extras]
|
| 2908 |
+
docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"]
|
| 2909 |
+
testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"]
|
| 2910 |
+
|
| 2911 |
+
[[package]]
|
| 2912 |
+
name = "pytest-xdist"
|
| 2913 |
+
version = "3.6.1"
|
| 2914 |
+
description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs"
|
| 2915 |
+
optional = false
|
| 2916 |
+
python-versions = ">=3.8"
|
| 2917 |
+
files = [
|
| 2918 |
+
{file = "pytest_xdist-3.6.1-py3-none-any.whl", hash = "sha256:9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7"},
|
| 2919 |
+
{file = "pytest_xdist-3.6.1.tar.gz", hash = "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d"},
|
| 2920 |
+
]
|
| 2921 |
+
|
| 2922 |
+
[package.dependencies]
|
| 2923 |
+
execnet = ">=2.1"
|
| 2924 |
+
pytest = ">=7.0.0"
|
| 2925 |
+
|
| 2926 |
+
[package.extras]
|
| 2927 |
+
psutil = ["psutil (>=3.0)"]
|
| 2928 |
+
setproctitle = ["setproctitle"]
|
| 2929 |
+
testing = ["filelock"]
|
| 2930 |
+
|
| 2931 |
[[package]]
|
| 2932 |
name = "python-dateutil"
|
| 2933 |
version = "2.9.0.post0"
|
|
|
|
| 4210 |
[metadata]
|
| 4211 |
lock-version = "2.0"
|
| 4212 |
python-versions = "^3.11,<3.12"
|
| 4213 |
+
content-hash = "527fd744fa60d7638490e59133486e40e1a5303635e9f0fd7286ce5ec97ad4d1"
|
pyproject.toml
CHANGED
|
@@ -28,6 +28,11 @@ pydantic = "^2.7.2"
|
|
| 28 |
dateparser = "^1.2.0"
|
| 29 |
pandas = "^2.2.2"
|
| 30 |
path = "^16.14.0"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
|
| 32 |
[tool.poetry.dependencies.uvicorn]
|
| 33 |
extras = [ "standard" ]
|
|
|
|
| 28 |
dateparser = "^1.2.0"
|
| 29 |
pandas = "^2.2.2"
|
| 30 |
path = "^16.14.0"
|
| 31 |
+
psycopg2-binary = "^2.9.9"
|
| 32 |
+
pytest-xdist = "^3.6.1"
|
| 33 |
+
pytest-asyncio = "^0.23.7"
|
| 34 |
+
httpx = "^0.27.0"
|
| 35 |
+
alembic = "^1.13.1"
|
| 36 |
|
| 37 |
[tool.poetry.dependencies.uvicorn]
|
| 38 |
extras = [ "standard" ]
|
tests/test_main.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from main import app
|
| 2 |
+
from fastapi.testclient import TestClient
|
| 3 |
+
|
| 4 |
+
client = TestClient(app)
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def test_read_main():
|
| 8 |
+
response = client.get("/")
|
| 9 |
+
assert response.status_code == 200
|
tests/test_postgresdb_connection.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pytest
|
| 2 |
+
from app.engine.postgresdb import get_db
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
@pytest.mark.skip
|
| 6 |
+
def test_postgres_db_connection():
|
| 7 |
+
"""
|
| 8 |
+
Tests the connection to the postgres db
|
| 9 |
+
"""
|
| 10 |
+
with get_db() as session:
|
| 11 |
+
# Execute a query to test the connection
|
| 12 |
+
result = session.execute(f"SELECT 1").scalar()
|
| 13 |
+
|
| 14 |
+
# Assert that the result is equal to 1
|
| 15 |
+
assert result == 1
|