📚 Documentação inicial do ALETHEIA

- MANUAL-PRODUTO.md: Manual do usuário final
- MANUAL-VENDAS.md: Estratégia comercial e vendas
- MANUAL-TECNICO.md: Infraestrutura e deploy
- README.md: Visão geral do projeto
This commit is contained in:
2026-02-10 15:08:15 -03:00
commit 20a26affaa
16617 changed files with 3202171 additions and 0 deletions

BIN
backend/aletheia.db Normal file

Binary file not shown.

0
backend/app/__init__.py Normal file
View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

15
backend/app/config.py Normal file
View File

@@ -0,0 +1,15 @@
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
DATABASE_URL: str = "sqlite+aiosqlite:///./aletheia.db"
SECRET_KEY: str = "aletheia-secret-key-change-in-production"
ALGORITHM: str = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24
OPENAI_API_KEY: str = ""
OPENAI_MODEL: str = "gpt-4o-mini"
FREE_SCAN_LIMIT: int = 3
class Config:
env_file = ".env"
settings = Settings()

17
backend/app/database.py Normal file
View File

@@ -0,0 +1,17 @@
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
from sqlalchemy.orm import DeclarativeBase
from app.config import settings
engine = create_async_engine(settings.DATABASE_URL, echo=False)
async_session = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
class Base(DeclarativeBase):
pass
async def get_db():
async with async_session() as session:
yield session
async def init_db():
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)

View File

@@ -0,0 +1,27 @@
import httpx
from typing import Optional
async def fetch_product(barcode: str) -> Optional[dict]:
url = f"https://world.openfoodfacts.org/api/v2/product/{barcode}.json"
headers = {"User-Agent": "Aletheia/1.0 (contato@aletheia.app)"}
try:
async with httpx.AsyncClient(timeout=10) as client:
resp = await client.get(url, headers=headers)
if resp.status_code != 200:
return None
data = resp.json()
if data.get("status") != 1:
return None
p = data["product"]
return {
"name": p.get("product_name") or p.get("product_name_pt") or "Produto desconhecido",
"brand": p.get("brands", ""),
"category": p.get("categories", ""),
"ingredients_text": p.get("ingredients_text") or p.get("ingredients_text_pt") or "",
"nutri_score": (p.get("nutriscore_grade") or "").lower(),
"nova_group": p.get("nova_group"),
"nutrition": p.get("nutriments", {}),
"image_url": p.get("image_url", ""),
}
except Exception:
return None

View File

@@ -0,0 +1,86 @@
import json
from openai import AsyncOpenAI
from app.config import settings
SYSTEM_PROMPT = """Você é um nutricionista especialista brasileiro que analisa rótulos de alimentos.
Responda SEMPRE em JSON válido com esta estrutura exata:
{
"score": <int 0-100>,
"summary": "<resumo em 2-3 frases para leigo, em português>",
"positives": ["<ponto positivo 1>", ...],
"negatives": ["<ponto negativo 1>", ...],
"ingredients": [
{
"name": "<nome no rótulo>",
"popular_name": "<nome popular ou null>",
"explanation": "<o que é, 1 frase>",
"classification": "<good|warning|bad>",
"reason": "<motivo da classificação, 1 frase>"
}
]
}
Critérios para o score:
- 90-100: Alimento natural, minimamente processado, sem aditivos
- 70-89: Bom, com poucos aditivos ou processamento leve
- 50-69: Médio, processado mas aceitável com moderação
- 30-49: Ruim, ultraprocessado com vários aditivos
- 0-29: Péssimo, alto em açúcar/sódio/gordura trans, muitos aditivos
Considere Nutri-Score, classificação NOVA, e ingredientes problemáticos.
Seja direto e honesto. Use linguagem simples."""
async def analyze_product(product_data: dict) -> dict:
if not settings.OPENAI_API_KEY:
return _mock_analysis(product_data)
client = AsyncOpenAI(api_key=settings.OPENAI_API_KEY)
user_msg = f"""Produto: {product_data.get('name', 'Desconhecido')}
Marca: {product_data.get('brand', '')}
Categoria: {product_data.get('category', '')}
Ingredientes: {product_data.get('ingredients_text', 'Não disponível')}
Nutri-Score: {product_data.get('nutri_score', 'N/A')}
NOVA: {product_data.get('nova_group', 'N/A')}
Analise este produto."""
try:
resp = await client.chat.completions.create(
model=settings.OPENAI_MODEL,
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_msg}
],
response_format={"type": "json_object"},
temperature=0.3,
timeout=15,
)
return json.loads(resp.choices[0].message.content)
except Exception as e:
print(f"OpenAI error: {e}")
return _mock_analysis(product_data)
def _mock_analysis(product_data: dict) -> dict:
ingredients = product_data.get("ingredients_text", "")
score = 50
if any(w in ingredients.lower() for w in ["açúcar", "sugar", "xarope", "glucose"]):
score -= 15
if any(w in ingredients.lower() for w in ["hidrogenada", "trans"]):
score -= 20
if product_data.get("nova_group") == 4:
score -= 10
ns = product_data.get("nutri_score", "")
if ns == "e": score -= 10
elif ns == "d": score -= 5
elif ns == "a": score += 15
elif ns == "b": score += 10
score = max(0, min(100, score))
return {
"score": score,
"summary": f"Análise baseada em regras para {product_data.get('name', 'este produto')}. Configure OPENAI_API_KEY para análise completa com IA.",
"positives": ["Dados nutricionais disponíveis"],
"negatives": ["Análise IA indisponível - usando fallback"],
"ingredients": []
}

27
backend/app/main.py Normal file
View File

@@ -0,0 +1,27 @@
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from contextlib import asynccontextmanager
from app.database import init_db
from app.routers import auth, scan
@asynccontextmanager
async def lifespan(app: FastAPI):
await init_db()
yield
app = FastAPI(title="Aletheia API", version="0.1.0", lifespan=lifespan)
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3080", "http://127.0.0.1:3080"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.include_router(auth.router)
app.include_router(scan.router)
@app.get("/api/health")
async def health():
return {"status": "ok", "app": "Aletheia API v0.1"}

View File

@@ -0,0 +1,5 @@
from app.models.user import User
from app.models.product import Product
from app.models.scan import Scan
__all__ = ["User", "Product", "Scan"]

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,17 @@
from sqlalchemy import Column, Integer, String, Text, DateTime
from datetime import datetime, timezone
from app.database import Base
class Product(Base):
__tablename__ = "products"
id = Column(Integer, primary_key=True, index=True)
barcode = Column(String, unique=True, index=True, nullable=False)
name = Column(String)
brand = Column(String)
category = Column(String)
ingredients_text = Column(Text)
nutri_score = Column(String)
nova_group = Column(Integer)
nutrition_json = Column(Text) # JSON string
image_url = Column(String)
updated_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))

View File

@@ -0,0 +1,15 @@
from sqlalchemy import Column, Integer, String, Text, ForeignKey, DateTime
from datetime import datetime, timezone
from app.database import Base
class Scan(Base):
__tablename__ = "scans"
id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
barcode = Column(String, nullable=False)
product_name = Column(String)
brand = Column(String)
score = Column(Integer)
summary = Column(Text)
analysis_json = Column(Text) # Full AI analysis as JSON
scanned_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))

View File

@@ -0,0 +1,12 @@
from sqlalchemy import Column, Integer, String, Boolean, DateTime
from datetime import datetime, timezone
from app.database import Base
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
email = Column(String, unique=True, index=True, nullable=False)
name = Column(String, nullable=False)
password_hash = Column(String, nullable=False)
is_premium = Column(Boolean, default=False)
created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))

View File

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,43 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from app.database import get_db
from app.models.user import User
from app.schemas.auth import RegisterRequest, LoginRequest, TokenResponse, UserResponse
from app.utils.security import hash_password, verify_password, create_access_token, get_current_user
router = APIRouter(prefix="/api/auth", tags=["auth"])
@router.post("/register", response_model=TokenResponse)
async def register(req: RegisterRequest, db: AsyncSession = Depends(get_db)):
existing = await db.execute(select(User).where(User.email == req.email))
if existing.scalar_one_or_none():
raise HTTPException(status_code=400, detail="Email já cadastrado")
user = User(email=req.email, name=req.name, password_hash=hash_password(req.password))
db.add(user)
await db.commit()
await db.refresh(user)
token = create_access_token({"sub": str(user.id)})
return TokenResponse(
access_token=token,
user={"id": user.id, "email": user.email, "name": user.name, "is_premium": user.is_premium}
)
@router.post("/login", response_model=TokenResponse)
async def login(req: LoginRequest, db: AsyncSession = Depends(get_db)):
result = await db.execute(select(User).where(User.email == req.email))
user = result.scalar_one_or_none()
if not user or not verify_password(req.password, user.password_hash):
raise HTTPException(status_code=401, detail="Email ou senha incorretos")
token = create_access_token({"sub": str(user.id)})
return TokenResponse(
access_token=token,
user={"id": user.id, "email": user.email, "name": user.name, "is_premium": user.is_premium}
)
@router.get("/me", response_model=UserResponse)
async def me(user: User = Depends(get_current_user)):
return UserResponse(id=user.id, email=user.email, name=user.name, is_premium=user.is_premium)

106
backend/app/routers/scan.py Normal file
View File

@@ -0,0 +1,106 @@
import json
from datetime import datetime, timezone, date
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func
from app.database import get_db
from app.models.user import User
from app.models.product import Product
from app.models.scan import Scan
from app.schemas.scan import ScanRequest, ScanResult, ScanHistoryItem
from app.utils.security import get_current_user
from app.integrations.open_food_facts import fetch_product
from app.integrations.openai_client import analyze_product
from app.config import settings
from app.services.seed import SEED_PRODUCTS
router = APIRouter(prefix="/api", tags=["scan"])
@router.post("/scan", response_model=ScanResult)
async def scan_product(req: ScanRequest, user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)):
# Rate limit check
if not user.is_premium:
today_start = datetime.now(timezone.utc).replace(hour=0, minute=0, second=0, microsecond=0)
result = await db.execute(
select(func.count(Scan.id)).where(Scan.user_id == user.id, Scan.scanned_at >= today_start)
)
count = result.scalar()
if count >= settings.FREE_SCAN_LIMIT:
raise HTTPException(status_code=429, detail=f"Limite de {settings.FREE_SCAN_LIMIT} scans/dia atingido. Faça upgrade para Premium!")
# Check local cache
result = await db.execute(select(Product).where(Product.barcode == req.barcode))
product = result.scalar_one_or_none()
product_data = None
source = "cache"
if product:
product_data = {
"name": product.name, "brand": product.brand, "category": product.category,
"ingredients_text": product.ingredients_text, "nutri_score": product.nutri_score,
"nova_group": product.nova_group, "nutrition": json.loads(product.nutrition_json or "{}"),
"image_url": product.image_url,
}
else:
# Check seed data
if req.barcode in SEED_PRODUCTS:
product_data = SEED_PRODUCTS[req.barcode].copy()
source = "seed"
else:
# Fetch from Open Food Facts
product_data = await fetch_product(req.barcode)
source = "open_food_facts"
if product_data:
new_product = Product(
barcode=req.barcode, name=product_data.get("name"), brand=product_data.get("brand"),
category=product_data.get("category"), ingredients_text=product_data.get("ingredients_text"),
nutri_score=product_data.get("nutri_score"), nova_group=product_data.get("nova_group"),
nutrition_json=json.dumps(product_data.get("nutrition", {})),
image_url=product_data.get("image_url", ""),
)
db.add(new_product)
await db.commit()
if not product_data:
raise HTTPException(status_code=404, detail="Produto não encontrado. Tente inserir manualmente.")
# AI Analysis
analysis = await analyze_product(product_data)
# Save scan
scan = Scan(
user_id=user.id, barcode=req.barcode, product_name=product_data.get("name"),
brand=product_data.get("brand"), score=analysis.get("score", 50),
summary=analysis.get("summary", ""), analysis_json=json.dumps(analysis),
)
db.add(scan)
await db.commit()
return ScanResult(
barcode=req.barcode,
product_name=product_data.get("name"),
brand=product_data.get("brand"),
category=product_data.get("category"),
image_url=product_data.get("image_url"),
score=analysis.get("score", 50),
summary=analysis.get("summary", ""),
positives=analysis.get("positives", []),
negatives=analysis.get("negatives", []),
ingredients=analysis.get("ingredients", []),
nutri_score=product_data.get("nutri_score"),
nova_group=product_data.get("nova_group"),
source=source,
)
@router.get("/history", response_model=list[ScanHistoryItem])
async def get_history(user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)):
result = await db.execute(
select(Scan).where(Scan.user_id == user.id).order_by(Scan.scanned_at.desc()).limit(50)
)
scans = result.scalars().all()
return [ScanHistoryItem(
id=s.id, barcode=s.barcode, product_name=s.product_name,
brand=s.brand, score=s.score, scanned_at=s.scanned_at
) for s in scans]

View File

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,21 @@
from pydantic import BaseModel, EmailStr
class RegisterRequest(BaseModel):
email: str
name: str
password: str
class LoginRequest(BaseModel):
email: str
password: str
class TokenResponse(BaseModel):
access_token: str
token_type: str = "bearer"
user: dict
class UserResponse(BaseModel):
id: int
email: str
name: str
is_premium: bool

View File

@@ -0,0 +1,36 @@
from pydantic import BaseModel
from typing import Optional, List
from datetime import datetime
class ScanRequest(BaseModel):
barcode: str
class IngredientAnalysis(BaseModel):
name: str
popular_name: Optional[str] = None
explanation: str
classification: str # "good", "warning", "bad"
reason: str
class ScanResult(BaseModel):
barcode: str
product_name: Optional[str] = None
brand: Optional[str] = None
category: Optional[str] = None
image_url: Optional[str] = None
score: int
summary: str
positives: List[str]
negatives: List[str]
ingredients: List[IngredientAnalysis]
nutri_score: Optional[str] = None
nova_group: Optional[int] = None
source: str = "open_food_facts"
class ScanHistoryItem(BaseModel):
id: int
barcode: str
product_name: Optional[str] = None
brand: Optional[str] = None
score: int
scanned_at: datetime

View File

Binary file not shown.

View File

@@ -0,0 +1,103 @@
# Seed data - Brazilian popular products
SEED_PRODUCTS = {
"7891000100103": {
"name": "Coca-Cola Original 350ml",
"brand": "Coca-Cola",
"category": "Refrigerantes",
"ingredients_text": "Água gaseificada, açúcar, extrato de noz de cola, cafeína, corante caramelo IV (INS 150d), acidulante ácido fosfórico (INS 338), aroma natural.",
"nutri_score": "e",
"nova_group": 4,
"nutrition": {"energy_kcal": 42, "sugars": 10.6, "fat": 0, "saturated_fat": 0, "sodium": 0.01, "fiber": 0, "proteins": 0},
"image_url": "",
},
"7891000053508": {
"name": "Nescau 2.0",
"brand": "Nestlé",
"category": "Achocolatados",
"ingredients_text": "Açúcar, cacau em pó, maltodextrina, composto lácteo (soro de leite em pó e gordura vegetal), minerais (ferro, zinco), sal, vitaminas (C, B3, B5, B6, A, ácido fólico, D, B12), emulsificante lecitina de soja, aromatizante.",
"nutri_score": "d",
"nova_group": 4,
"nutrition": {"energy_kcal": 380, "sugars": 72, "fat": 3.5, "saturated_fat": 2, "sodium": 0.1, "fiber": 3.5, "proteins": 5},
"image_url": "",
},
"7891000305232": {
"name": "Miojo Lámen Galinha Caipira",
"brand": "Nissin",
"category": "Macarrão instantâneo",
"ingredients_text": "Farinha de trigo enriquecida com ferro e ácido fólico, gordura vegetal, sal, reguladores de acidez (carbonato de potássio e carbonato de sódio), espessante goma guar, corante natural de cúrcuma, realçador de sabor glutamato monossódico, aromas, açúcar, cebola, alho, salsa.",
"nutri_score": "d",
"nova_group": 4,
"nutrition": {"energy_kcal": 436, "sugars": 4, "fat": 17, "saturated_fat": 8, "sodium": 1.6, "fiber": 2, "proteins": 9},
"image_url": "",
},
"7891962057620": {
"name": "Toddy Original",
"brand": "PepsiCo",
"category": "Achocolatados",
"ingredients_text": "Açúcar, cacau em pó, maltodextrina, minerais (fosfato de cálcio, pirofosfato férrico, óxido de zinco), vitaminas (C, PP, B6, B2, B1, A, ácido fólico, D, B12), sal, emulsificante lecitina de soja e aromatizante.",
"nutri_score": "d",
"nova_group": 4,
"nutrition": {"energy_kcal": 375, "sugars": 77, "fat": 2.2, "saturated_fat": 1.4, "sodium": 0.05, "fiber": 4.5, "proteins": 3.9},
"image_url": "",
},
"7891910000197": {
"name": "Guaraná Antarctica 350ml",
"brand": "Ambev",
"category": "Refrigerantes",
"ingredients_text": "Água gaseificada, açúcar, extrato de guaraná, acidulante ácido cítrico, aroma natural e corante caramelo IV.",
"nutri_score": "e",
"nova_group": 4,
"nutrition": {"energy_kcal": 40, "sugars": 10, "fat": 0, "saturated_fat": 0, "sodium": 0.01, "fiber": 0, "proteins": 0},
"image_url": "",
},
"7891150029392": {
"name": "Leite Moça Tradicional 395g",
"brand": "Nestlé",
"category": "Leite condensado",
"ingredients_text": "Leite integral, açúcar e lactose.",
"nutri_score": "d",
"nova_group": 2,
"nutrition": {"energy_kcal": 321, "sugars": 55, "fat": 8, "saturated_fat": 5, "sodium": 0.12, "fiber": 0, "proteins": 7},
"image_url": "",
},
"7896004800011": {
"name": "Biscoito Maizena Vitarella",
"brand": "Vitarella",
"category": "Biscoitos",
"ingredients_text": "Farinha de trigo enriquecida com ferro e ácido fólico, açúcar, gordura vegetal, amido de milho, soro de leite em pó, sal, fermentos químicos (bicarbonato de amônio, bicarbonato de sódio e fosfato monocálcico), emulsificante lecitina de soja, aromatizante.",
"nutri_score": "d",
"nova_group": 4,
"nutrition": {"energy_kcal": 443, "sugars": 22, "fat": 14, "saturated_fat": 6, "sodium": 0.3, "fiber": 1.5, "proteins": 7},
"image_url": "",
},
"7891000244203": {
"name": "Iogurte Nestlé Grego Tradicional",
"brand": "Nestlé",
"category": "Iogurtes",
"ingredients_text": "Leite integral e/ou reconstituído, preparado de açúcar (açúcar, água, amido modificado, cloreto de cálcio e conservador sorbato de potássio), creme de leite, proteínas do leite, fermento lácteo.",
"nutri_score": "c",
"nova_group": 4,
"nutrition": {"energy_kcal": 134, "sugars": 15, "fat": 6, "saturated_fat": 3.8, "sodium": 0.05, "fiber": 0, "proteins": 4.8},
"image_url": "",
},
"7622300830236": {
"name": "Biscoito Oreo Original",
"brand": "Mondelez",
"category": "Biscoitos recheados",
"ingredients_text": "Farinha de trigo enriquecida com ferro e ácido fólico, açúcar, gordura vegetal, cacau em pó, amido de milho, sal, fermentos químicos, emulsificante lecitina de soja, aromatizante vanilina.",
"nutri_score": "e",
"nova_group": 4,
"nutrition": {"energy_kcal": 476, "sugars": 36, "fat": 20, "saturated_fat": 10, "sodium": 0.4, "fiber": 2, "proteins": 5},
"image_url": "",
},
"7891000362006": {
"name": "Aveia Quaker Flocos Finos",
"brand": "Quaker",
"category": "Cereais",
"ingredients_text": "Aveia em flocos finos.",
"nutri_score": "a",
"nova_group": 1,
"nutrition": {"energy_kcal": 366, "sugars": 1, "fat": 7.5, "saturated_fat": 1.3, "sodium": 0.002, "fiber": 9.5, "proteins": 14},
"image_url": "",
},
}

Binary file not shown.

View File

@@ -0,0 +1,43 @@
from passlib.context import CryptContext
from jose import jwt, JWTError
from datetime import datetime, timedelta, timezone
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from app.config import settings
from app.database import get_db
from app.models.user import User
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
security = HTTPBearer()
def hash_password(password: str) -> str:
return pwd_context.hash(password)
def verify_password(plain: str, hashed: str) -> bool:
return pwd_context.verify(plain, hashed)
def create_access_token(data: dict) -> str:
to_encode = data.copy()
expire = datetime.now(timezone.utc) + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
to_encode.update({"exp": expire})
return jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
async def get_current_user(
credentials: HTTPAuthorizationCredentials = Depends(security),
db: AsyncSession = Depends(get_db)
) -> User:
try:
payload = jwt.decode(credentials.credentials, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
user_id = payload.get("sub")
if user_id is None:
raise HTTPException(status_code=401, detail="Invalid token")
except JWTError:
raise HTTPException(status_code=401, detail="Invalid token")
result = await db.execute(select(User).where(User.id == int(user_id)))
user = result.scalar_one_or_none()
if user is None:
raise HTTPException(status_code=401, detail="User not found")
return user

11
backend/requirements.txt Normal file
View File

@@ -0,0 +1,11 @@
fastapi==0.115.0
uvicorn[standard]==0.30.6
sqlalchemy==2.0.35
python-jose[cryptography]==3.3.0
passlib[bcrypt]==1.7.4
httpx==0.27.2
openai==1.51.0
bcrypt==4.2.0
pydantic-settings==2.5.2
python-multipart==0.0.12
aiosqlite==0.20.0

View File

@@ -0,0 +1,247 @@
<#
.Synopsis
Activate a Python virtual environment for the current PowerShell session.
.Description
Pushes the python executable for a virtual environment to the front of the
$Env:PATH environment variable and sets the prompt to signify that you are
in a Python virtual environment. Makes use of the command line switches as
well as the `pyvenv.cfg` file values present in the virtual environment.
.Parameter VenvDir
Path to the directory that contains the virtual environment to activate. The
default value for this is the parent of the directory that the Activate.ps1
script is located within.
.Parameter Prompt
The prompt prefix to display when this virtual environment is activated. By
default, this prompt is the name of the virtual environment folder (VenvDir)
surrounded by parentheses and followed by a single space (ie. '(.venv) ').
.Example
Activate.ps1
Activates the Python virtual environment that contains the Activate.ps1 script.
.Example
Activate.ps1 -Verbose
Activates the Python virtual environment that contains the Activate.ps1 script,
and shows extra information about the activation as it executes.
.Example
Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv
Activates the Python virtual environment located in the specified location.
.Example
Activate.ps1 -Prompt "MyPython"
Activates the Python virtual environment that contains the Activate.ps1 script,
and prefixes the current prompt with the specified string (surrounded in
parentheses) while the virtual environment is active.
.Notes
On Windows, it may be required to enable this Activate.ps1 script by setting the
execution policy for the user. You can do this by issuing the following PowerShell
command:
PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
For more information on Execution Policies:
https://go.microsoft.com/fwlink/?LinkID=135170
#>
Param(
[Parameter(Mandatory = $false)]
[String]
$VenvDir,
[Parameter(Mandatory = $false)]
[String]
$Prompt
)
<# Function declarations --------------------------------------------------- #>
<#
.Synopsis
Remove all shell session elements added by the Activate script, including the
addition of the virtual environment's Python executable from the beginning of
the PATH variable.
.Parameter NonDestructive
If present, do not remove this function from the global namespace for the
session.
#>
function global:deactivate ([switch]$NonDestructive) {
# Revert to original values
# The prior prompt:
if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) {
Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt
Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT
}
# The prior PYTHONHOME:
if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) {
Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME
Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME
}
# The prior PATH:
if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) {
Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH
Remove-Item -Path Env:_OLD_VIRTUAL_PATH
}
# Just remove the VIRTUAL_ENV altogether:
if (Test-Path -Path Env:VIRTUAL_ENV) {
Remove-Item -Path env:VIRTUAL_ENV
}
# Just remove VIRTUAL_ENV_PROMPT altogether.
if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) {
Remove-Item -Path env:VIRTUAL_ENV_PROMPT
}
# Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether:
if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) {
Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force
}
# Leave deactivate function in the global namespace if requested:
if (-not $NonDestructive) {
Remove-Item -Path function:deactivate
}
}
<#
.Description
Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the
given folder, and returns them in a map.
For each line in the pyvenv.cfg file, if that line can be parsed into exactly
two strings separated by `=` (with any amount of whitespace surrounding the =)
then it is considered a `key = value` line. The left hand string is the key,
the right hand is the value.
If the value starts with a `'` or a `"` then the first and last character is
stripped from the value before being captured.
.Parameter ConfigDir
Path to the directory that contains the `pyvenv.cfg` file.
#>
function Get-PyVenvConfig(
[String]
$ConfigDir
) {
Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg"
# Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue).
$pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue
# An empty map will be returned if no config file is found.
$pyvenvConfig = @{ }
if ($pyvenvConfigPath) {
Write-Verbose "File exists, parse `key = value` lines"
$pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath
$pyvenvConfigContent | ForEach-Object {
$keyval = $PSItem -split "\s*=\s*", 2
if ($keyval[0] -and $keyval[1]) {
$val = $keyval[1]
# Remove extraneous quotations around a string value.
if ("'""".Contains($val.Substring(0, 1))) {
$val = $val.Substring(1, $val.Length - 2)
}
$pyvenvConfig[$keyval[0]] = $val
Write-Verbose "Adding Key: '$($keyval[0])'='$val'"
}
}
}
return $pyvenvConfig
}
<# Begin Activate script --------------------------------------------------- #>
# Determine the containing directory of this script
$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
$VenvExecDir = Get-Item -Path $VenvExecPath
Write-Verbose "Activation script is located in path: '$VenvExecPath'"
Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)"
Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)"
# Set values required in priority: CmdLine, ConfigFile, Default
# First, get the location of the virtual environment, it might not be
# VenvExecDir if specified on the command line.
if ($VenvDir) {
Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values"
}
else {
Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir."
$VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/")
Write-Verbose "VenvDir=$VenvDir"
}
# Next, read the `pyvenv.cfg` file to determine any required value such
# as `prompt`.
$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir
# Next, set the prompt from the command line, or the config file, or
# just use the name of the virtual environment folder.
if ($Prompt) {
Write-Verbose "Prompt specified as argument, using '$Prompt'"
}
else {
Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value"
if ($pyvenvCfg -and $pyvenvCfg['prompt']) {
Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'"
$Prompt = $pyvenvCfg['prompt'];
}
else {
Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)"
Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'"
$Prompt = Split-Path -Path $venvDir -Leaf
}
}
Write-Verbose "Prompt = '$Prompt'"
Write-Verbose "VenvDir='$VenvDir'"
# Deactivate any currently active virtual environment, but leave the
# deactivate function in place.
deactivate -nondestructive
# Now set the environment variable VIRTUAL_ENV, used by many tools to determine
# that there is an activated venv.
$env:VIRTUAL_ENV = $VenvDir
if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) {
Write-Verbose "Setting prompt to '$Prompt'"
# Set the prompt to include the env name
# Make sure _OLD_VIRTUAL_PROMPT is global
function global:_OLD_VIRTUAL_PROMPT { "" }
Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT
New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt
function global:prompt {
Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) "
_OLD_VIRTUAL_PROMPT
}
$env:VIRTUAL_ENV_PROMPT = $Prompt
}
# Clear PYTHONHOME
if (Test-Path -Path Env:PYTHONHOME) {
Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME
Remove-Item -Path Env:PYTHONHOME
}
# Add the venv to the PATH
Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH
$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH"

70
backend/venv/bin/activate Normal file
View File

@@ -0,0 +1,70 @@
# This file must be used with "source bin/activate" *from bash*
# You cannot run it directly
deactivate () {
# reset old environment variables
if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
PATH="${_OLD_VIRTUAL_PATH:-}"
export PATH
unset _OLD_VIRTUAL_PATH
fi
if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
export PYTHONHOME
unset _OLD_VIRTUAL_PYTHONHOME
fi
# Call hash to forget past commands. Without forgetting
# past commands the $PATH changes we made may not be respected
hash -r 2> /dev/null
if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
PS1="${_OLD_VIRTUAL_PS1:-}"
export PS1
unset _OLD_VIRTUAL_PS1
fi
unset VIRTUAL_ENV
unset VIRTUAL_ENV_PROMPT
if [ ! "${1:-}" = "nondestructive" ] ; then
# Self destruct!
unset -f deactivate
fi
}
# unset irrelevant variables
deactivate nondestructive
# on Windows, a path can contain colons and backslashes and has to be converted:
if [ "${OSTYPE:-}" = "cygwin" ] || [ "${OSTYPE:-}" = "msys" ] ; then
# transform D:\path\to\venv to /d/path/to/venv on MSYS
# and to /cygdrive/d/path/to/venv on Cygwin
export VIRTUAL_ENV=$(cygpath /home/kernelpanic/projetos_jarvis/aletheia/backend/venv)
else
# use the path as-is
export VIRTUAL_ENV=/home/kernelpanic/projetos_jarvis/aletheia/backend/venv
fi
_OLD_VIRTUAL_PATH="$PATH"
PATH="$VIRTUAL_ENV/"bin":$PATH"
export PATH
# unset PYTHONHOME if set
# this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
# could use `if (set -u; : $PYTHONHOME) ;` in bash
if [ -n "${PYTHONHOME:-}" ] ; then
_OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}"
unset PYTHONHOME
fi
if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
_OLD_VIRTUAL_PS1="${PS1:-}"
PS1='(venv) '"${PS1:-}"
export PS1
VIRTUAL_ENV_PROMPT='(venv) '
export VIRTUAL_ENV_PROMPT
fi
# Call hash to forget past commands. Without forgetting
# past commands the $PATH changes we made may not be respected
hash -r 2> /dev/null

View File

@@ -0,0 +1,27 @@
# This file must be used with "source bin/activate.csh" *from csh*.
# You cannot run it directly.
# Created by Davide Di Blasi <davidedb@gmail.com>.
# Ported to Python 3.3 venv by Andrew Svetlov <andrew.svetlov@gmail.com>
alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate'
# Unset irrelevant variables.
deactivate nondestructive
setenv VIRTUAL_ENV /home/kernelpanic/projetos_jarvis/aletheia/backend/venv
set _OLD_VIRTUAL_PATH="$PATH"
setenv PATH "$VIRTUAL_ENV/"bin":$PATH"
set _OLD_VIRTUAL_PROMPT="$prompt"
if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then
set prompt = '(venv) '"$prompt"
setenv VIRTUAL_ENV_PROMPT '(venv) '
endif
alias pydoc python -m pydoc
rehash

View File

@@ -0,0 +1,69 @@
# This file must be used with "source <venv>/bin/activate.fish" *from fish*
# (https://fishshell.com/). You cannot run it directly.
function deactivate -d "Exit virtual environment and return to normal shell environment"
# reset old environment variables
if test -n "$_OLD_VIRTUAL_PATH"
set -gx PATH $_OLD_VIRTUAL_PATH
set -e _OLD_VIRTUAL_PATH
end
if test -n "$_OLD_VIRTUAL_PYTHONHOME"
set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME
set -e _OLD_VIRTUAL_PYTHONHOME
end
if test -n "$_OLD_FISH_PROMPT_OVERRIDE"
set -e _OLD_FISH_PROMPT_OVERRIDE
# prevents error when using nested fish instances (Issue #93858)
if functions -q _old_fish_prompt
functions -e fish_prompt
functions -c _old_fish_prompt fish_prompt
functions -e _old_fish_prompt
end
end
set -e VIRTUAL_ENV
set -e VIRTUAL_ENV_PROMPT
if test "$argv[1]" != "nondestructive"
# Self-destruct!
functions -e deactivate
end
end
# Unset irrelevant variables.
deactivate nondestructive
set -gx VIRTUAL_ENV /home/kernelpanic/projetos_jarvis/aletheia/backend/venv
set -gx _OLD_VIRTUAL_PATH $PATH
set -gx PATH "$VIRTUAL_ENV/"bin $PATH
# Unset PYTHONHOME if set.
if set -q PYTHONHOME
set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME
set -e PYTHONHOME
end
if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
# fish uses a function instead of an env var to generate the prompt.
# Save the current fish_prompt function as the function _old_fish_prompt.
functions -c fish_prompt _old_fish_prompt
# With the original prompt function renamed, we can override with our own.
function fish_prompt
# Save the return status of the last command.
set -l old_status $status
# Output the venv prompt; color taken from the blue of the Python logo.
printf "%s%s%s" (set_color 4B8BBE) '(venv) ' (set_color normal)
# Restore the return status of the previous command.
echo "exit $old_status" | .
# Output the original/"old" prompt.
_old_fish_prompt
end
set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV"
set -gx VIRTUAL_ENV_PROMPT '(venv) '
end

8
backend/venv/bin/distro Executable file
View File

@@ -0,0 +1,8 @@
#!/home/kernelpanic/projetos_jarvis/aletheia/backend/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from distro.distro import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
backend/venv/bin/dotenv Executable file
View File

@@ -0,0 +1,8 @@
#!/home/kernelpanic/projetos_jarvis/aletheia/backend/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from dotenv.__main__ import cli
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(cli())

8
backend/venv/bin/fastapi Executable file
View File

@@ -0,0 +1,8 @@
#!/home/kernelpanic/projetos_jarvis/aletheia/backend/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from fastapi.cli import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
backend/venv/bin/httpx Executable file
View File

@@ -0,0 +1,8 @@
#!/home/kernelpanic/projetos_jarvis/aletheia/backend/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from httpx import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
backend/venv/bin/openai Executable file
View File

@@ -0,0 +1,8 @@
#!/home/kernelpanic/projetos_jarvis/aletheia/backend/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from openai.cli import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
backend/venv/bin/pip Executable file
View File

@@ -0,0 +1,8 @@
#!/home/kernelpanic/projetos_jarvis/aletheia/backend/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pip._internal.cli.main import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
backend/venv/bin/pip3 Executable file
View File

@@ -0,0 +1,8 @@
#!/home/kernelpanic/projetos_jarvis/aletheia/backend/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pip._internal.cli.main import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
backend/venv/bin/pip3.12 Executable file
View File

@@ -0,0 +1,8 @@
#!/home/kernelpanic/projetos_jarvis/aletheia/backend/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pip._internal.cli.main import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
backend/venv/bin/pyrsa-decrypt Executable file
View File

@@ -0,0 +1,8 @@
#!/home/kernelpanic/projetos_jarvis/aletheia/backend/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from rsa.cli import decrypt
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(decrypt())

8
backend/venv/bin/pyrsa-encrypt Executable file
View File

@@ -0,0 +1,8 @@
#!/home/kernelpanic/projetos_jarvis/aletheia/backend/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from rsa.cli import encrypt
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(encrypt())

8
backend/venv/bin/pyrsa-keygen Executable file
View File

@@ -0,0 +1,8 @@
#!/home/kernelpanic/projetos_jarvis/aletheia/backend/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from rsa.cli import keygen
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(keygen())

View File

@@ -0,0 +1,8 @@
#!/home/kernelpanic/projetos_jarvis/aletheia/backend/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from rsa.util import private_to_public
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(private_to_public())

8
backend/venv/bin/pyrsa-sign Executable file
View File

@@ -0,0 +1,8 @@
#!/home/kernelpanic/projetos_jarvis/aletheia/backend/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from rsa.cli import sign
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(sign())

8
backend/venv/bin/pyrsa-verify Executable file
View File

@@ -0,0 +1,8 @@
#!/home/kernelpanic/projetos_jarvis/aletheia/backend/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from rsa.cli import verify
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(verify())

1
backend/venv/bin/python Symbolic link
View File

@@ -0,0 +1 @@
python3

1
backend/venv/bin/python3 Symbolic link
View File

@@ -0,0 +1 @@
/usr/bin/python3

1
backend/venv/bin/python3.12 Symbolic link
View File

@@ -0,0 +1 @@
python3

8
backend/venv/bin/tqdm Executable file
View File

@@ -0,0 +1,8 @@
#!/home/kernelpanic/projetos_jarvis/aletheia/backend/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from tqdm.cli import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
backend/venv/bin/uvicorn Executable file
View File

@@ -0,0 +1,8 @@
#!/home/kernelpanic/projetos_jarvis/aletheia/backend/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from uvicorn.main import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

8
backend/venv/bin/watchfiles Executable file
View File

@@ -0,0 +1,8 @@
#!/home/kernelpanic/projetos_jarvis/aletheia/backend/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from watchfiles.cli import cli
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(cli())

8
backend/venv/bin/websockets Executable file
View File

@@ -0,0 +1,8 @@
#!/home/kernelpanic/projetos_jarvis/aletheia/backend/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from websockets.cli import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View File

@@ -0,0 +1,164 @@
/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */
/* Greenlet object interface */
#ifndef Py_GREENLETOBJECT_H
#define Py_GREENLETOBJECT_H
#include <Python.h>
#ifdef __cplusplus
extern "C" {
#endif
/* This is deprecated and undocumented. It does not change. */
#define GREENLET_VERSION "1.0.0"
#ifndef GREENLET_MODULE
#define implementation_ptr_t void*
#endif
typedef struct _greenlet {
PyObject_HEAD
PyObject* weakreflist;
PyObject* dict;
implementation_ptr_t pimpl;
} PyGreenlet;
#define PyGreenlet_Check(op) (op && PyObject_TypeCheck(op, &PyGreenlet_Type))
/* C API functions */
/* Total number of symbols that are exported */
#define PyGreenlet_API_pointers 12
#define PyGreenlet_Type_NUM 0
#define PyExc_GreenletError_NUM 1
#define PyExc_GreenletExit_NUM 2
#define PyGreenlet_New_NUM 3
#define PyGreenlet_GetCurrent_NUM 4
#define PyGreenlet_Throw_NUM 5
#define PyGreenlet_Switch_NUM 6
#define PyGreenlet_SetParent_NUM 7
#define PyGreenlet_MAIN_NUM 8
#define PyGreenlet_STARTED_NUM 9
#define PyGreenlet_ACTIVE_NUM 10
#define PyGreenlet_GET_PARENT_NUM 11
#ifndef GREENLET_MODULE
/* This section is used by modules that uses the greenlet C API */
static void** _PyGreenlet_API = NULL;
# define PyGreenlet_Type \
(*(PyTypeObject*)_PyGreenlet_API[PyGreenlet_Type_NUM])
# define PyExc_GreenletError \
((PyObject*)_PyGreenlet_API[PyExc_GreenletError_NUM])
# define PyExc_GreenletExit \
((PyObject*)_PyGreenlet_API[PyExc_GreenletExit_NUM])
/*
* PyGreenlet_New(PyObject *args)
*
* greenlet.greenlet(run, parent=None)
*/
# define PyGreenlet_New \
(*(PyGreenlet * (*)(PyObject * run, PyGreenlet * parent)) \
_PyGreenlet_API[PyGreenlet_New_NUM])
/*
* PyGreenlet_GetCurrent(void)
*
* greenlet.getcurrent()
*/
# define PyGreenlet_GetCurrent \
(*(PyGreenlet * (*)(void)) _PyGreenlet_API[PyGreenlet_GetCurrent_NUM])
/*
* PyGreenlet_Throw(
* PyGreenlet *greenlet,
* PyObject *typ,
* PyObject *val,
* PyObject *tb)
*
* g.throw(...)
*/
# define PyGreenlet_Throw \
(*(PyObject * (*)(PyGreenlet * self, \
PyObject * typ, \
PyObject * val, \
PyObject * tb)) \
_PyGreenlet_API[PyGreenlet_Throw_NUM])
/*
* PyGreenlet_Switch(PyGreenlet *greenlet, PyObject *args)
*
* g.switch(*args, **kwargs)
*/
# define PyGreenlet_Switch \
(*(PyObject * \
(*)(PyGreenlet * greenlet, PyObject * args, PyObject * kwargs)) \
_PyGreenlet_API[PyGreenlet_Switch_NUM])
/*
* PyGreenlet_SetParent(PyObject *greenlet, PyObject *new_parent)
*
* g.parent = new_parent
*/
# define PyGreenlet_SetParent \
(*(int (*)(PyGreenlet * greenlet, PyGreenlet * nparent)) \
_PyGreenlet_API[PyGreenlet_SetParent_NUM])
/*
* PyGreenlet_GetParent(PyObject* greenlet)
*
* return greenlet.parent;
*
* This could return NULL even if there is no exception active.
* If it does not return NULL, you are responsible for decrementing the
* reference count.
*/
# define PyGreenlet_GetParent \
(*(PyGreenlet* (*)(PyGreenlet*)) \
_PyGreenlet_API[PyGreenlet_GET_PARENT_NUM])
/*
* deprecated, undocumented alias.
*/
# define PyGreenlet_GET_PARENT PyGreenlet_GetParent
# define PyGreenlet_MAIN \
(*(int (*)(PyGreenlet*)) \
_PyGreenlet_API[PyGreenlet_MAIN_NUM])
# define PyGreenlet_STARTED \
(*(int (*)(PyGreenlet*)) \
_PyGreenlet_API[PyGreenlet_STARTED_NUM])
# define PyGreenlet_ACTIVE \
(*(int (*)(PyGreenlet*)) \
_PyGreenlet_API[PyGreenlet_ACTIVE_NUM])
/* Macro that imports greenlet and initializes C API */
/* NOTE: This has actually moved to ``greenlet._greenlet._C_API``, but we
keep the older definition to be sure older code that might have a copy of
the header still works. */
# define PyGreenlet_Import() \
{ \
_PyGreenlet_API = (void**)PyCapsule_Import("greenlet._C_API", 0); \
}
#endif /* GREENLET_MODULE */
#ifdef __cplusplus
}
#endif
#endif /* !Py_GREENLETOBJECT_H */

View File

@@ -0,0 +1,19 @@
Copyright 2005-2024 SQLAlchemy authors and contributors <see AUTHORS file>.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,242 @@
Metadata-Version: 2.1
Name: SQLAlchemy
Version: 2.0.35
Summary: Database Abstraction Library
Home-page: https://www.sqlalchemy.org
Author: Mike Bayer
Author-email: mike_mp@zzzcomputing.com
License: MIT
Project-URL: Documentation, https://docs.sqlalchemy.org
Project-URL: Issue Tracker, https://github.com/sqlalchemy/sqlalchemy/
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Database :: Front-Ends
Requires-Python: >=3.7
Description-Content-Type: text/x-rst
License-File: LICENSE
Requires-Dist: typing-extensions >=4.6.0
Requires-Dist: greenlet !=0.4.17 ; python_version < "3.13" and (platform_machine == "aarch64" or (platform_machine == "ppc64le" or (platform_machine == "x86_64" or (platform_machine == "amd64" or (platform_machine == "AMD64" or (platform_machine == "win32" or platform_machine == "WIN32"))))))
Requires-Dist: importlib-metadata ; python_version < "3.8"
Provides-Extra: aiomysql
Requires-Dist: greenlet !=0.4.17 ; extra == 'aiomysql'
Requires-Dist: aiomysql >=0.2.0 ; extra == 'aiomysql'
Provides-Extra: aioodbc
Requires-Dist: greenlet !=0.4.17 ; extra == 'aioodbc'
Requires-Dist: aioodbc ; extra == 'aioodbc'
Provides-Extra: aiosqlite
Requires-Dist: greenlet !=0.4.17 ; extra == 'aiosqlite'
Requires-Dist: aiosqlite ; extra == 'aiosqlite'
Requires-Dist: typing-extensions !=3.10.0.1 ; extra == 'aiosqlite'
Provides-Extra: asyncio
Requires-Dist: greenlet !=0.4.17 ; extra == 'asyncio'
Provides-Extra: asyncmy
Requires-Dist: greenlet !=0.4.17 ; extra == 'asyncmy'
Requires-Dist: asyncmy !=0.2.4,!=0.2.6,>=0.2.3 ; extra == 'asyncmy'
Provides-Extra: mariadb_connector
Requires-Dist: mariadb !=1.1.2,!=1.1.5,>=1.0.1 ; extra == 'mariadb_connector'
Provides-Extra: mssql
Requires-Dist: pyodbc ; extra == 'mssql'
Provides-Extra: mssql_pymssql
Requires-Dist: pymssql ; extra == 'mssql_pymssql'
Provides-Extra: mssql_pyodbc
Requires-Dist: pyodbc ; extra == 'mssql_pyodbc'
Provides-Extra: mypy
Requires-Dist: mypy >=0.910 ; extra == 'mypy'
Provides-Extra: mysql
Requires-Dist: mysqlclient >=1.4.0 ; extra == 'mysql'
Provides-Extra: mysql_connector
Requires-Dist: mysql-connector-python ; extra == 'mysql_connector'
Provides-Extra: oracle
Requires-Dist: cx-oracle >=8 ; extra == 'oracle'
Provides-Extra: oracle_oracledb
Requires-Dist: oracledb >=1.0.1 ; extra == 'oracle_oracledb'
Provides-Extra: postgresql
Requires-Dist: psycopg2 >=2.7 ; extra == 'postgresql'
Provides-Extra: postgresql_asyncpg
Requires-Dist: greenlet !=0.4.17 ; extra == 'postgresql_asyncpg'
Requires-Dist: asyncpg ; extra == 'postgresql_asyncpg'
Provides-Extra: postgresql_pg8000
Requires-Dist: pg8000 >=1.29.1 ; extra == 'postgresql_pg8000'
Provides-Extra: postgresql_psycopg
Requires-Dist: psycopg >=3.0.7 ; extra == 'postgresql_psycopg'
Provides-Extra: postgresql_psycopg2binary
Requires-Dist: psycopg2-binary ; extra == 'postgresql_psycopg2binary'
Provides-Extra: postgresql_psycopg2cffi
Requires-Dist: psycopg2cffi ; extra == 'postgresql_psycopg2cffi'
Provides-Extra: postgresql_psycopgbinary
Requires-Dist: psycopg[binary] >=3.0.7 ; extra == 'postgresql_psycopgbinary'
Provides-Extra: pymysql
Requires-Dist: pymysql ; extra == 'pymysql'
Provides-Extra: sqlcipher
Requires-Dist: sqlcipher3-binary ; extra == 'sqlcipher'
SQLAlchemy
==========
|PyPI| |Python| |Downloads|
.. |PyPI| image:: https://img.shields.io/pypi/v/sqlalchemy
:target: https://pypi.org/project/sqlalchemy
:alt: PyPI
.. |Python| image:: https://img.shields.io/pypi/pyversions/sqlalchemy
:target: https://pypi.org/project/sqlalchemy
:alt: PyPI - Python Version
.. |Downloads| image:: https://static.pepy.tech/badge/sqlalchemy/month
:target: https://pepy.tech/project/sqlalchemy
:alt: PyPI - Downloads
The Python SQL Toolkit and Object Relational Mapper
Introduction
-------------
SQLAlchemy is the Python SQL toolkit and Object Relational Mapper
that gives application developers the full power and
flexibility of SQL. SQLAlchemy provides a full suite
of well known enterprise-level persistence patterns,
designed for efficient and high-performing database
access, adapted into a simple and Pythonic domain
language.
Major SQLAlchemy features include:
* An industrial strength ORM, built
from the core on the identity map, unit of work,
and data mapper patterns. These patterns
allow transparent persistence of objects
using a declarative configuration system.
Domain models
can be constructed and manipulated naturally,
and changes are synchronized with the
current transaction automatically.
* A relationally-oriented query system, exposing
the full range of SQL's capabilities
explicitly, including joins, subqueries,
correlation, and most everything else,
in terms of the object model.
Writing queries with the ORM uses the same
techniques of relational composition you use
when writing SQL. While you can drop into
literal SQL at any time, it's virtually never
needed.
* A comprehensive and flexible system
of eager loading for related collections and objects.
Collections are cached within a session,
and can be loaded on individual access, all
at once using joins, or by query per collection
across the full result set.
* A Core SQL construction system and DBAPI
interaction layer. The SQLAlchemy Core is
separate from the ORM and is a full database
abstraction layer in its own right, and includes
an extensible Python-based SQL expression
language, schema metadata, connection pooling,
type coercion, and custom types.
* All primary and foreign key constraints are
assumed to be composite and natural. Surrogate
integer primary keys are of course still the
norm, but SQLAlchemy never assumes or hardcodes
to this model.
* Database introspection and generation. Database
schemas can be "reflected" in one step into
Python structures representing database metadata;
those same structures can then generate
CREATE statements right back out - all within
the Core, independent of the ORM.
SQLAlchemy's philosophy:
* SQL databases behave less and less like object
collections the more size and performance start to
matter; object collections behave less and less like
tables and rows the more abstraction starts to matter.
SQLAlchemy aims to accommodate both of these
principles.
* An ORM doesn't need to hide the "R". A relational
database provides rich, set-based functionality
that should be fully exposed. SQLAlchemy's
ORM provides an open-ended set of patterns
that allow a developer to construct a custom
mediation layer between a domain model and
a relational schema, turning the so-called
"object relational impedance" issue into
a distant memory.
* The developer, in all cases, makes all decisions
regarding the design, structure, and naming conventions
of both the object model as well as the relational
schema. SQLAlchemy only provides the means
to automate the execution of these decisions.
* With SQLAlchemy, there's no such thing as
"the ORM generated a bad query" - you
retain full control over the structure of
queries, including how joins are organized,
how subqueries and correlation is used, what
columns are requested. Everything SQLAlchemy
does is ultimately the result of a developer-initiated
decision.
* Don't use an ORM if the problem doesn't need one.
SQLAlchemy consists of a Core and separate ORM
component. The Core offers a full SQL expression
language that allows Pythonic construction
of SQL constructs that render directly to SQL
strings for a target database, returning
result sets that are essentially enhanced DBAPI
cursors.
* Transactions should be the norm. With SQLAlchemy's
ORM, nothing goes to permanent storage until
commit() is called. SQLAlchemy encourages applications
to create a consistent means of delineating
the start and end of a series of operations.
* Never render a literal value in a SQL statement.
Bound parameters are used to the greatest degree
possible, allowing query optimizers to cache
query plans effectively and making SQL injection
attacks a non-issue.
Documentation
-------------
Latest documentation is at:
https://www.sqlalchemy.org/docs/
Installation / Requirements
---------------------------
Full documentation for installation is at
`Installation <https://www.sqlalchemy.org/docs/intro.html#installation>`_.
Getting Help / Development / Bug reporting
------------------------------------------
Please refer to the `SQLAlchemy Community Guide <https://www.sqlalchemy.org/support.html>`_.
Code of Conduct
---------------
Above all, SQLAlchemy places great emphasis on polite, thoughtful, and
constructive communication between users and developers.
Please see our current Code of Conduct at
`Code of Conduct <https://www.sqlalchemy.org/codeofconduct.html>`_.
License
-------
SQLAlchemy is distributed under the `MIT license
<https://www.opensource.org/licenses/mit-license.php>`_.

View File

@@ -0,0 +1,530 @@
SQLAlchemy-2.0.35.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
SQLAlchemy-2.0.35.dist-info/LICENSE,sha256=PA9Zq4h9BB3mpOUv_j6e212VIt6Qn66abNettue-MpM,1100
SQLAlchemy-2.0.35.dist-info/METADATA,sha256=nz-ukujebAhwlZl0txMOxlkTwDyPwTn3tWuKTcw8OMU,9632
SQLAlchemy-2.0.35.dist-info/RECORD,,
SQLAlchemy-2.0.35.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
SQLAlchemy-2.0.35.dist-info/WHEEL,sha256=7B4nnId14TToQHuAKpxbDLCJbNciqBsV-mvXE2hVLJc,151
SQLAlchemy-2.0.35.dist-info/top_level.txt,sha256=rp-ZgB7D8G11ivXON5VGPjupT1voYmWqkciDt5Uaw_Q,11
sqlalchemy/__init__.py,sha256=xHEMNoAWZaZfX2Zdm2gnVT8EWjaBfg6HpzG4ncSmPrk,13033
sqlalchemy/__pycache__/__init__.cpython-312.pyc,,
sqlalchemy/__pycache__/events.cpython-312.pyc,,
sqlalchemy/__pycache__/exc.cpython-312.pyc,,
sqlalchemy/__pycache__/inspection.cpython-312.pyc,,
sqlalchemy/__pycache__/log.cpython-312.pyc,,
sqlalchemy/__pycache__/schema.cpython-312.pyc,,
sqlalchemy/__pycache__/types.cpython-312.pyc,,
sqlalchemy/connectors/__init__.py,sha256=PzXPqZqi3BzEnrs1eW0DcsR4lyknAzhhN9rWcQ97hb4,476
sqlalchemy/connectors/__pycache__/__init__.cpython-312.pyc,,
sqlalchemy/connectors/__pycache__/aioodbc.cpython-312.pyc,,
sqlalchemy/connectors/__pycache__/asyncio.cpython-312.pyc,,
sqlalchemy/connectors/__pycache__/pyodbc.cpython-312.pyc,,
sqlalchemy/connectors/aioodbc.py,sha256=GSTiNMO9h0qjPxgqaxDwWZ8HvhWMFNVR6MJQnN1oc40,5288
sqlalchemy/connectors/asyncio.py,sha256=Hq2bkXmG6-KO_RfCrwMqx4oGH-uH1Z1WWKqPWNjz8p4,6138
sqlalchemy/connectors/pyodbc.py,sha256=t7AjyxIOnaWg3CrlUEpBs4Y5l0HFdNt3P_cSSKhbi0Y,8501
sqlalchemy/cyextension/__init__.py,sha256=GzhhN8cjMnDTE0qerlUlpbrNmFPHQWCZ4Gk74OAxl04,244
sqlalchemy/cyextension/__pycache__/__init__.cpython-312.pyc,,
sqlalchemy/cyextension/collections.cpython-312-x86_64-linux-gnu.so,sha256=wiVAQHnu9pZiSNMZmfxQQs6cS19-erq0DXux92G4VSo,1932256
sqlalchemy/cyextension/collections.pyx,sha256=L7DZ3DGKpgw2MT2ZZRRxCnrcyE5pU1NAFowWgAzQPEc,12571
sqlalchemy/cyextension/immutabledict.cpython-312-x86_64-linux-gnu.so,sha256=rl6xddEXaRQGh9OlPP2LDlAmSP_8OrLrVv4gJbcPiCc,805632
sqlalchemy/cyextension/immutabledict.pxd,sha256=3x3-rXG5eRQ7bBnktZ-OJ9-6ft8zToPmTDOd92iXpB0,291
sqlalchemy/cyextension/immutabledict.pyx,sha256=KfDTYbTfebstE8xuqAtuXsHNAK0_b5q_ymUiinUe_xs,3535
sqlalchemy/cyextension/processors.cpython-312-x86_64-linux-gnu.so,sha256=7JFk5KtZ2DQzB4TKTz7-Zb7EWTUHOVTw7-sfKHQm4MY,530680
sqlalchemy/cyextension/processors.pyx,sha256=R1rHsGLEaGeBq5VeCydjClzYlivERIJ9B-XLOJlf2MQ,1792
sqlalchemy/cyextension/resultproxy.cpython-312-x86_64-linux-gnu.so,sha256=05hidqye-dCbUfWu9RYtdtftx0Fo9tTsBaO6Tp5sSQg,621328
sqlalchemy/cyextension/resultproxy.pyx,sha256=eWLdyBXiBy_CLQrF5ScfWJm7X0NeelscSXedtj1zv9Q,2725
sqlalchemy/cyextension/util.cpython-312-x86_64-linux-gnu.so,sha256=dfsFk5a4zF5Z9Afrxu6JB8GBoRcfVSp9KuSwFIgtmlU,950928
sqlalchemy/cyextension/util.pyx,sha256=B85orxa9LddLuQEaDoVSq1XmAXIbLKxrxpvuB8ogV_o,2530
sqlalchemy/dialects/__init__.py,sha256=Kos9Gf5JZg1Vg6GWaCqEbD6e0r1jCwCmcnJIfcxDdcY,1770
sqlalchemy/dialects/__pycache__/__init__.cpython-312.pyc,,
sqlalchemy/dialects/__pycache__/_typing.cpython-312.pyc,,
sqlalchemy/dialects/_typing.py,sha256=hyv0nKucX2gI8ispB1IsvaUgrEPn9zEcq9hS7kfstEw,888
sqlalchemy/dialects/mssql/__init__.py,sha256=r5t8wFRNtBQoiUWh0WfIEWzXZW6f3D0uDt6NZTW_7Cc,1880
sqlalchemy/dialects/mssql/__pycache__/__init__.cpython-312.pyc,,
sqlalchemy/dialects/mssql/__pycache__/aioodbc.cpython-312.pyc,,
sqlalchemy/dialects/mssql/__pycache__/base.cpython-312.pyc,,
sqlalchemy/dialects/mssql/__pycache__/information_schema.cpython-312.pyc,,
sqlalchemy/dialects/mssql/__pycache__/json.cpython-312.pyc,,
sqlalchemy/dialects/mssql/__pycache__/provision.cpython-312.pyc,,
sqlalchemy/dialects/mssql/__pycache__/pymssql.cpython-312.pyc,,
sqlalchemy/dialects/mssql/__pycache__/pyodbc.cpython-312.pyc,,
sqlalchemy/dialects/mssql/aioodbc.py,sha256=UQd9ecSMIML713TDnLAviuBVJle7P7i1FtqGZZePk2Y,2022
sqlalchemy/dialects/mssql/base.py,sha256=TQekFOsor8Rc-cnDPmbq_JLQekKrHPtUdBdNsCYFw7w,132447
sqlalchemy/dialects/mssql/information_schema.py,sha256=HswjDc6y0mPXCf_x6VyylHlBdBa4PSY6Evxmmlch700,8084
sqlalchemy/dialects/mssql/json.py,sha256=evUACW2O62TAPq8B7QIPagz7jfc664ql9ms68JqiYzg,4816
sqlalchemy/dialects/mssql/provision.py,sha256=ZAtt6Div9NLIngMs8kyloxfphw0KDNMsnRCAVd7-esE,5593
sqlalchemy/dialects/mssql/pymssql.py,sha256=LAv43q4vBCB85OsAwHQItaQUYTYIO0QJ-jvzaBrswmY,4097
sqlalchemy/dialects/mssql/pyodbc.py,sha256=vwM-vBlmRwrqxOc73P0sFOrBSwn24wzc5IkEOpalbXQ,27056
sqlalchemy/dialects/mysql/__init__.py,sha256=bxbi4hkysUK2OOVvr1F49akUj1cky27kKb07tgFzI9U,2153
sqlalchemy/dialects/mysql/__pycache__/__init__.cpython-312.pyc,,
sqlalchemy/dialects/mysql/__pycache__/aiomysql.cpython-312.pyc,,
sqlalchemy/dialects/mysql/__pycache__/asyncmy.cpython-312.pyc,,
sqlalchemy/dialects/mysql/__pycache__/base.cpython-312.pyc,,
sqlalchemy/dialects/mysql/__pycache__/cymysql.cpython-312.pyc,,
sqlalchemy/dialects/mysql/__pycache__/dml.cpython-312.pyc,,
sqlalchemy/dialects/mysql/__pycache__/enumerated.cpython-312.pyc,,
sqlalchemy/dialects/mysql/__pycache__/expression.cpython-312.pyc,,
sqlalchemy/dialects/mysql/__pycache__/json.cpython-312.pyc,,
sqlalchemy/dialects/mysql/__pycache__/mariadb.cpython-312.pyc,,
sqlalchemy/dialects/mysql/__pycache__/mariadbconnector.cpython-312.pyc,,
sqlalchemy/dialects/mysql/__pycache__/mysqlconnector.cpython-312.pyc,,
sqlalchemy/dialects/mysql/__pycache__/mysqldb.cpython-312.pyc,,
sqlalchemy/dialects/mysql/__pycache__/provision.cpython-312.pyc,,
sqlalchemy/dialects/mysql/__pycache__/pymysql.cpython-312.pyc,,
sqlalchemy/dialects/mysql/__pycache__/pyodbc.cpython-312.pyc,,
sqlalchemy/dialects/mysql/__pycache__/reflection.cpython-312.pyc,,
sqlalchemy/dialects/mysql/__pycache__/reserved_words.cpython-312.pyc,,
sqlalchemy/dialects/mysql/__pycache__/types.cpython-312.pyc,,
sqlalchemy/dialects/mysql/aiomysql.py,sha256=-oMZnCqNsSki8mlQRTWIwiQPT1OVdZIuANkb90q8LAs,9999
sqlalchemy/dialects/mysql/asyncmy.py,sha256=YpuuOh8VknEeqHqUXQGfQ3jhfO3Xb-vZv78Jq5cscJ0,10067
sqlalchemy/dialects/mysql/base.py,sha256=8shrZRSnVwDXtl6ybaO6cvul_RZ34zEWqvpYW5sNfOQ,120986
sqlalchemy/dialects/mysql/cymysql.py,sha256=eXT1ry0w_qRxjiO24M980c-8PZ9qSsbhqBHntjEiKB0,2300
sqlalchemy/dialects/mysql/dml.py,sha256=HXJMAvimJsqvhj3UZO4vW_6LkF5RqaKbHvklAjor7yU,7645
sqlalchemy/dialects/mysql/enumerated.py,sha256=ipEPPQqoXfFwcywNdcLlZCEzHBtnitHRah1Gn6nItcg,8448
sqlalchemy/dialects/mysql/expression.py,sha256=lsmQCHKwfPezUnt27d2kR6ohk4IRFCA64KBS16kx5dc,4097
sqlalchemy/dialects/mysql/json.py,sha256=l6MEZ0qp8FgiRrIQvOMhyEJq0q6OqiEnvDTx5Cbt9uQ,2269
sqlalchemy/dialects/mysql/mariadb.py,sha256=kTfBLioLKk4JFFst4TY_iWqPtnvvQXFHknLfm89H2N8,853
sqlalchemy/dialects/mysql/mariadbconnector.py,sha256=_S1aV93kyP52Nvj7HR9weThML4oUvSLsLqiVFdoLR2o,8623
sqlalchemy/dialects/mysql/mysqlconnector.py,sha256=oq3mtsNOMldUjs32JbJG2u3Hy3DObyVzUUMYfOkwkHg,5729
sqlalchemy/dialects/mysql/mysqldb.py,sha256=qUBbA6STeYGozutyTxHCo5p1W3p59QFFS2FwCgPrjBA,9503
sqlalchemy/dialects/mysql/provision.py,sha256=Jnk8UO9_Apd2odR2IQFLrscCfAmYxuBKcB8giS3bBog,3575
sqlalchemy/dialects/mysql/pymysql.py,sha256=GUnSHd2M2uKjmN46Hheymtm26g7phEgwYOXrX0zLY8M,4083
sqlalchemy/dialects/mysql/pyodbc.py,sha256=072crI4qVyPhajYvHnsfFeSrNjLFVPIjBQKo5uyz5yk,4297
sqlalchemy/dialects/mysql/reflection.py,sha256=3u34YwT1JJh3uThGZJZ3FKdnUcT7v08QB-tAl1r7VRk,22834
sqlalchemy/dialects/mysql/reserved_words.py,sha256=ucKX2p2c3UnMq2ayZuOHuf73eXhu7SKsOsTlIN1Q83I,9258
sqlalchemy/dialects/mysql/types.py,sha256=L5cTCsMT1pTedszNEM3jSxFNZEMcHQLprYCZ0vmfsnA,24343
sqlalchemy/dialects/oracle/__init__.py,sha256=p4-2gw7TT0bX_MoJXTGD4i8WHctYsK9kCRbkpzykBrc,1493
sqlalchemy/dialects/oracle/__pycache__/__init__.cpython-312.pyc,,
sqlalchemy/dialects/oracle/__pycache__/base.cpython-312.pyc,,
sqlalchemy/dialects/oracle/__pycache__/cx_oracle.cpython-312.pyc,,
sqlalchemy/dialects/oracle/__pycache__/dictionary.cpython-312.pyc,,
sqlalchemy/dialects/oracle/__pycache__/oracledb.cpython-312.pyc,,
sqlalchemy/dialects/oracle/__pycache__/provision.cpython-312.pyc,,
sqlalchemy/dialects/oracle/__pycache__/types.cpython-312.pyc,,
sqlalchemy/dialects/oracle/base.py,sha256=HykzMCkN1LSRteoEttWb_ln9Q0YmOJ5tLbJan7TuWZ4,119699
sqlalchemy/dialects/oracle/cx_oracle.py,sha256=q8Nyj15UZCE2TWOmxuWp5ZsxiCiGMzqfd_9UkmjIja0,55235
sqlalchemy/dialects/oracle/dictionary.py,sha256=7WMrbPkqo8ZdGjaEZyQr-5f2pajSOF1OTGb8P97z8-g,19519
sqlalchemy/dialects/oracle/oracledb.py,sha256=fZRKGqNIwW9LG4i8yDOXABrucbfzn_yC86Od-BJ3PcM,13619
sqlalchemy/dialects/oracle/provision.py,sha256=O9ZpF4OG6Cx4mMzLRfZwhs8dZjrJETWR402n9c7726A,8304
sqlalchemy/dialects/oracle/types.py,sha256=QK3hJvWzKnnCe3oD3rItwEEIwcoBze8qGg7VFOvVlIk,8231
sqlalchemy/dialects/postgresql/__init__.py,sha256=wwnNAq4wDQzrlPRzDNB06ayuq3L2HNO99nzeEvq-YcU,3892
sqlalchemy/dialects/postgresql/__pycache__/__init__.cpython-312.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/_psycopg_common.cpython-312.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/array.cpython-312.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/asyncpg.cpython-312.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/base.cpython-312.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/dml.cpython-312.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/ext.cpython-312.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/hstore.cpython-312.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/json.cpython-312.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/named_types.cpython-312.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/operators.cpython-312.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/pg8000.cpython-312.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/pg_catalog.cpython-312.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/provision.cpython-312.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/psycopg.cpython-312.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/psycopg2.cpython-312.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/psycopg2cffi.cpython-312.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/ranges.cpython-312.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/types.cpython-312.pyc,,
sqlalchemy/dialects/postgresql/_psycopg_common.py,sha256=7TudtgsPiSB8O5kX8W8KxcNYR8t5h_UHb86b_ChL0P8,5696
sqlalchemy/dialects/postgresql/array.py,sha256=bWcame7ntmI_Kx6gmBX0-chwADFdLHeCvaDQ4iX8id8,13734
sqlalchemy/dialects/postgresql/asyncpg.py,sha256=se1HXkikKQFcR2D-15jS6iKIaQs-M8Y8ke99ih0Y4NM,41132
sqlalchemy/dialects/postgresql/base.py,sha256=ed49Ode09deJF3jXr8V5sSHTwVoFVq0dlvNdP3mJaBQ,178989
sqlalchemy/dialects/postgresql/dml.py,sha256=Pc69Le6qzmUHHb1FT5zeUSD31dWm6SBgdCAGW89cs3s,11212
sqlalchemy/dialects/postgresql/ext.py,sha256=1bZ--iNh2O9ym7l2gXZX48yP3yMO4dqb9RpYro2Mj2Q,16262
sqlalchemy/dialects/postgresql/hstore.py,sha256=otAx-RTDfpi_tcXkMuQV0JOIXtYgevgnsikLKKOkI6U,11541
sqlalchemy/dialects/postgresql/json.py,sha256=73nmtG-7TN01DytjIJnG8CHa8Q7KwlRdN0bhx4fEAT0,11590
sqlalchemy/dialects/postgresql/named_types.py,sha256=3IV1ufo7zJjKmX4VtGDEnoXE6xEqLJAtGG82IiqHXwY,17594
sqlalchemy/dialects/postgresql/operators.py,sha256=NsAaWun_tL3d_be0fs9YL6T4LPKK6crnmFxxIJHgyeY,2808
sqlalchemy/dialects/postgresql/pg8000.py,sha256=3yoekiWSF-xnaWMqG76XrYPMqerg-42TdmfsW_ivK9E,18640
sqlalchemy/dialects/postgresql/pg_catalog.py,sha256=hY3NXEUHxTWD4umhd2aowNu3laC-61Q_qQ_pReyXTUM,9254
sqlalchemy/dialects/postgresql/provision.py,sha256=t6TZj0XaWG9zrpCjNr0oJRjAC_WQzaNdp3kaKJIbS8I,5770
sqlalchemy/dialects/postgresql/psycopg.py,sha256=ACkfuT87vUJEW4kJyUqDYTwlnl5u0FZFlDcvLzxNzFQ,23226
sqlalchemy/dialects/postgresql/psycopg2.py,sha256=kwEnflz5bAqJcuO_20eYiCtha_a4m_tg5_lppdDnaeU,31998
sqlalchemy/dialects/postgresql/psycopg2cffi.py,sha256=M7wAYSL6Pvt-4nbfacAHGyyw4XMKJ_bQZ1tc1pBtIdg,1756
sqlalchemy/dialects/postgresql/ranges.py,sha256=6CgV7qkxEMJ9AQsiibo_XBLJYzGh-2ZxpG83sRaesVY,32949
sqlalchemy/dialects/postgresql/types.py,sha256=Jfxqw9JaKNOq29JRWBublywgb3lLMyzx8YZI7CXpS2s,7300
sqlalchemy/dialects/sqlite/__init__.py,sha256=lp9DIggNn349M-7IYhUA8et8--e8FRExWD2V_r1LJk4,1182
sqlalchemy/dialects/sqlite/__pycache__/__init__.cpython-312.pyc,,
sqlalchemy/dialects/sqlite/__pycache__/aiosqlite.cpython-312.pyc,,
sqlalchemy/dialects/sqlite/__pycache__/base.cpython-312.pyc,,
sqlalchemy/dialects/sqlite/__pycache__/dml.cpython-312.pyc,,
sqlalchemy/dialects/sqlite/__pycache__/json.cpython-312.pyc,,
sqlalchemy/dialects/sqlite/__pycache__/provision.cpython-312.pyc,,
sqlalchemy/dialects/sqlite/__pycache__/pysqlcipher.cpython-312.pyc,,
sqlalchemy/dialects/sqlite/__pycache__/pysqlite.cpython-312.pyc,,
sqlalchemy/dialects/sqlite/aiosqlite.py,sha256=g3qGV6jmiXabWyb3282g_Nmxtj1jThxGSe9C9yalb-U,12345
sqlalchemy/dialects/sqlite/base.py,sha256=P15AcHoVWS20mMNQqnCfj94owUsTEX2ULtRn290AoF0,97837
sqlalchemy/dialects/sqlite/dml.py,sha256=9GE55WvwoktKy2fHeT-Wbc9xPHgsbh5oBfd_fckMH5Q,8443
sqlalchemy/dialects/sqlite/json.py,sha256=Eoplbb_4dYlfrtmQaI8Xddd2suAIHA-IdbDQYM-LIhs,2777
sqlalchemy/dialects/sqlite/provision.py,sha256=UCpmwxf4IWlrpb2eLHGbPTpCFVbdI_KAh2mKtjiLYao,5632
sqlalchemy/dialects/sqlite/pysqlcipher.py,sha256=OL2S_05DK9kllZj6DOz7QtEl7jI7syxjW6woS725ii4,5356
sqlalchemy/dialects/sqlite/pysqlite.py,sha256=aDp47n0J509kl2hDchoaBKXEQVZtkux54DwfKytUAe4,28068
sqlalchemy/dialects/type_migration_guidelines.txt,sha256=-uHNdmYFGB7bzUNT6i8M5nb4j6j9YUKAtW4lcBZqsMg,8239
sqlalchemy/engine/__init__.py,sha256=Stb2oV6l8w65JvqEo6J4qtKoApcmOpXy3AAxQud4C1o,2818
sqlalchemy/engine/__pycache__/__init__.cpython-312.pyc,,
sqlalchemy/engine/__pycache__/_py_processors.cpython-312.pyc,,
sqlalchemy/engine/__pycache__/_py_row.cpython-312.pyc,,
sqlalchemy/engine/__pycache__/_py_util.cpython-312.pyc,,
sqlalchemy/engine/__pycache__/base.cpython-312.pyc,,
sqlalchemy/engine/__pycache__/characteristics.cpython-312.pyc,,
sqlalchemy/engine/__pycache__/create.cpython-312.pyc,,
sqlalchemy/engine/__pycache__/cursor.cpython-312.pyc,,
sqlalchemy/engine/__pycache__/default.cpython-312.pyc,,
sqlalchemy/engine/__pycache__/events.cpython-312.pyc,,
sqlalchemy/engine/__pycache__/interfaces.cpython-312.pyc,,
sqlalchemy/engine/__pycache__/mock.cpython-312.pyc,,
sqlalchemy/engine/__pycache__/processors.cpython-312.pyc,,
sqlalchemy/engine/__pycache__/reflection.cpython-312.pyc,,
sqlalchemy/engine/__pycache__/result.cpython-312.pyc,,
sqlalchemy/engine/__pycache__/row.cpython-312.pyc,,
sqlalchemy/engine/__pycache__/strategies.cpython-312.pyc,,
sqlalchemy/engine/__pycache__/url.cpython-312.pyc,,
sqlalchemy/engine/__pycache__/util.cpython-312.pyc,,
sqlalchemy/engine/_py_processors.py,sha256=j9i_lcYYQOYJMcsDerPxI0sVFBIlX5sqoYMdMJlgWPI,3744
sqlalchemy/engine/_py_row.py,sha256=wSqoUFzLOJ1f89kgDb6sJm9LUrF5LMFpXPcK1vUsKcs,3787
sqlalchemy/engine/_py_util.py,sha256=f2DI3AN1kv6EplelowesCVpwS8hSXNufRkZoQmJtSH8,2484
sqlalchemy/engine/base.py,sha256=frWSMmt3dlentYH4QNN3cijdGzp8NbunColUZwWsWgI,122958
sqlalchemy/engine/characteristics.py,sha256=N3kbvw_ApMh86wb5yAGnxtPYD4YRhYMWion1H_aVZBI,4765
sqlalchemy/engine/create.py,sha256=mYJtOG2ZKM8sgyfjpGpamW15RDU7JXi5s6iibbJHMIs,33206
sqlalchemy/engine/cursor.py,sha256=cFq61yrw76k-QR_xNUBWuL-Zeyb14ltG-6jo2Q2iuuw,76392
sqlalchemy/engine/default.py,sha256=2wwKKdsagb3QTajRSEw8Hl-EnQ-LmRxy822xOGyenHc,84648
sqlalchemy/engine/events.py,sha256=c0unNFFiHzTAvkUtXoJaxzMFMDwurBkHiiUhuN8qluc,37381
sqlalchemy/engine/interfaces.py,sha256=fcVHOmnMo7JZLHzgSKoK3QsdVHH7kJ_AmrDvwW9Ka3k,112936
sqlalchemy/engine/mock.py,sha256=yvpxgFmRw5G4QsHeF-ZwQGHKES-HqQOucTxFtN1uzdk,4179
sqlalchemy/engine/processors.py,sha256=XyfINKbo-2fjN-mW55YybvFyQMOil50_kVqsunahkNs,2379
sqlalchemy/engine/reflection.py,sha256=gwGs8y7x6py5z-ZWx3hQqQrwpHepMCTJyQcFwWJjPlw,75364
sqlalchemy/engine/result.py,sha256=j6BI4Wj2bziQNQG5OlG_Cm4KcNWY9AoYvTXVlJUU-D8,77603
sqlalchemy/engine/row.py,sha256=9AAQo9zYDL88GcZ3bjcQTwMT-YIcuGTSMAyTfmBJ_yM,12032
sqlalchemy/engine/strategies.py,sha256=DqFSWaXJPL-29Omot9O0aOcuGL8KmCGyOvnPGDkAJoE,442
sqlalchemy/engine/url.py,sha256=8eWkUaIUyDExOcJ2D4xJXRcn4OY1GQJ3Q2duSX6UGAg,30784
sqlalchemy/engine/util.py,sha256=bNirO8k1S8yOW61uNH-a9QrWtAJ9VGFgbiR0lk1lUQU,5682
sqlalchemy/event/__init__.py,sha256=KBrp622xojnC3FFquxa2JsMamwAbfkvzfv6Op0NKiYc,997
sqlalchemy/event/__pycache__/__init__.cpython-312.pyc,,
sqlalchemy/event/__pycache__/api.cpython-312.pyc,,
sqlalchemy/event/__pycache__/attr.cpython-312.pyc,,
sqlalchemy/event/__pycache__/base.cpython-312.pyc,,
sqlalchemy/event/__pycache__/legacy.cpython-312.pyc,,
sqlalchemy/event/__pycache__/registry.cpython-312.pyc,,
sqlalchemy/event/api.py,sha256=DtDVgjKSorOfp9MGJ7fgMWrj4seC_hkwF4D8CW1RFZU,8226
sqlalchemy/event/attr.py,sha256=X8QeHGK4ioSYht1vkhc11f606_mq_t91jMNIT314ubs,20751
sqlalchemy/event/base.py,sha256=270OShTD17-bSFUFnPtKdVnB0NFJZ2AouYPo1wT0aJw,15127
sqlalchemy/event/legacy.py,sha256=teMPs00fO-4g8a_z2omcVKkYce5wj_1uvJO2n2MIeuo,8227
sqlalchemy/event/registry.py,sha256=nfTSSyhjZZXc5wseWB4sXn-YibSc0LKX8mg17XlWmAo,10835
sqlalchemy/events.py,sha256=k-ZD38aSPD29LYhED7CBqttp5MDVVx_YSaWC2-cu9ec,525
sqlalchemy/exc.py,sha256=M_8-O1hd8i6gbyx-TapV400p_Lxq2QqTGMXUAO-YgCc,23976
sqlalchemy/ext/__init__.py,sha256=S1fGKAbycnQDV01gs-JWGaFQ9GCD4QHwKcU2wnugg_o,322
sqlalchemy/ext/__pycache__/__init__.cpython-312.pyc,,
sqlalchemy/ext/__pycache__/associationproxy.cpython-312.pyc,,
sqlalchemy/ext/__pycache__/automap.cpython-312.pyc,,
sqlalchemy/ext/__pycache__/baked.cpython-312.pyc,,
sqlalchemy/ext/__pycache__/compiler.cpython-312.pyc,,
sqlalchemy/ext/__pycache__/horizontal_shard.cpython-312.pyc,,
sqlalchemy/ext/__pycache__/hybrid.cpython-312.pyc,,
sqlalchemy/ext/__pycache__/indexable.cpython-312.pyc,,
sqlalchemy/ext/__pycache__/instrumentation.cpython-312.pyc,,
sqlalchemy/ext/__pycache__/mutable.cpython-312.pyc,,
sqlalchemy/ext/__pycache__/orderinglist.cpython-312.pyc,,
sqlalchemy/ext/__pycache__/serializer.cpython-312.pyc,,
sqlalchemy/ext/associationproxy.py,sha256=5O5ANHARO8jytvqBQmOu-QjNVE4Hh3tfYquqKAj5ajs,65771
sqlalchemy/ext/asyncio/__init__.py,sha256=1OqSxEyIUn7RWLGyO12F-jAUIvk1I6DXlVy80-Gvkds,1317
sqlalchemy/ext/asyncio/__pycache__/__init__.cpython-312.pyc,,
sqlalchemy/ext/asyncio/__pycache__/base.cpython-312.pyc,,
sqlalchemy/ext/asyncio/__pycache__/engine.cpython-312.pyc,,
sqlalchemy/ext/asyncio/__pycache__/exc.cpython-312.pyc,,
sqlalchemy/ext/asyncio/__pycache__/result.cpython-312.pyc,,
sqlalchemy/ext/asyncio/__pycache__/scoping.cpython-312.pyc,,
sqlalchemy/ext/asyncio/__pycache__/session.cpython-312.pyc,,
sqlalchemy/ext/asyncio/base.py,sha256=fl7wxZD9KjgFiCtG3WXrYjHEvanamcsodCqq9pH9lOk,8905
sqlalchemy/ext/asyncio/engine.py,sha256=S_IRWX4QAjj2veLSu4Y3gKBIXkKQt7_2StJAK2_KUDY,48190
sqlalchemy/ext/asyncio/exc.py,sha256=8sII7VMXzs2TrhizhFQMzSfcroRtiesq8o3UwLfXSgQ,639
sqlalchemy/ext/asyncio/result.py,sha256=ID2eh-NHW-lnNFTxbKhje8fr-tnsucUsiw_jcpGcSPc,30409
sqlalchemy/ext/asyncio/scoping.py,sha256=UxHAFxtWKqA7TEozyN2h7MJyzSspTCrS-1SlgQLTExo,52608
sqlalchemy/ext/asyncio/session.py,sha256=mkFFC1C2mPuopz3BwkfSVTlp3vuIDc8hxiQx5ky5rvc,63103
sqlalchemy/ext/automap.py,sha256=r0mUSyogNyqdBL4m9AA1NXbLiTLQmtvyQymsssNEipo,61581
sqlalchemy/ext/baked.py,sha256=H6T1il7GY84BhzPFj49UECSpZh_eBuiHomA-QIsYOYQ,17807
sqlalchemy/ext/compiler.py,sha256=ONPoxoKD2yUS9R2-oOhmPsA7efm-Bs0BXo7HE1dGlsU,20391
sqlalchemy/ext/declarative/__init__.py,sha256=20psLdFQbbOWfpdXHZ0CTY6I1k4UqXvKemNVu1LvPOI,1818
sqlalchemy/ext/declarative/__pycache__/__init__.cpython-312.pyc,,
sqlalchemy/ext/declarative/__pycache__/extensions.cpython-312.pyc,,
sqlalchemy/ext/declarative/extensions.py,sha256=uCjN1GisQt54AjqYnKYzJdUjnGd2pZBW47WWdPlS7FE,19547
sqlalchemy/ext/horizontal_shard.py,sha256=wuwAPnHymln0unSBnyx-cpX0AfESKSsypaSQTYCvzDk,16750
sqlalchemy/ext/hybrid.py,sha256=IYkCaPZ29gm2cPKPg0cWMkLCEqMykD8-JJTvgacGbmc,52458
sqlalchemy/ext/indexable.py,sha256=UkTelbydKCdKelzbv3HWFFavoET9WocKaGRPGEOVfN8,11032
sqlalchemy/ext/instrumentation.py,sha256=sg8ghDjdHSODFXh_jAmpgemnNX1rxCeeXEG3-PMdrNk,15707
sqlalchemy/ext/mutable.py,sha256=L5ZkHBGYhMaqO75Xtyrk2DBR44RDk0g6Rz2HzHH0F8Q,37355
sqlalchemy/ext/mypy/__init__.py,sha256=0WebDIZmqBD0OTq5JLtd_PmfF9JGxe4d4Qv3Ml3PKUg,241
sqlalchemy/ext/mypy/__pycache__/__init__.cpython-312.pyc,,
sqlalchemy/ext/mypy/__pycache__/apply.cpython-312.pyc,,
sqlalchemy/ext/mypy/__pycache__/decl_class.cpython-312.pyc,,
sqlalchemy/ext/mypy/__pycache__/infer.cpython-312.pyc,,
sqlalchemy/ext/mypy/__pycache__/names.cpython-312.pyc,,
sqlalchemy/ext/mypy/__pycache__/plugin.cpython-312.pyc,,
sqlalchemy/ext/mypy/__pycache__/util.cpython-312.pyc,,
sqlalchemy/ext/mypy/apply.py,sha256=Aek_-XA1eXihT4attxhfE43yBKtCgsxBSb--qgZKUqc,10550
sqlalchemy/ext/mypy/decl_class.py,sha256=1vVJRII2apnLTUbc5HkJS6Z2GueaUv_eKvhbqh7Wik4,17384
sqlalchemy/ext/mypy/infer.py,sha256=KVnmLFEVS33Al8pUKI7MJbJQu3KeveBUMl78EluBORw,19369
sqlalchemy/ext/mypy/names.py,sha256=Q3ef8XQBgVm9WUwlItqlYCXDNi_kbV5DdLEgbtEMEI8,10479
sqlalchemy/ext/mypy/plugin.py,sha256=74ML8LI9xar0V86oCxnPFv5FQGEEfUzK64vOay4BKFs,9750
sqlalchemy/ext/mypy/util.py,sha256=DKRaurkXHI2lAMAAcEO5GLXbX_m2Xqy7l_juh8Byf5U,9960
sqlalchemy/ext/orderinglist.py,sha256=TGYbsGH72wEZcFNQDYDsZg9OSPuzf__P8YX8_2HtYUo,14384
sqlalchemy/ext/serializer.py,sha256=D0g4jMZkRk0Gjr0L-FZe81SR63h0Zs-9JzuWtT_SD7k,6140
sqlalchemy/future/__init__.py,sha256=q2mw-gxk_xoxJLEvRoyMha3vO1xSRHrslcExOHZwmPA,512
sqlalchemy/future/__pycache__/__init__.cpython-312.pyc,,
sqlalchemy/future/__pycache__/engine.cpython-312.pyc,,
sqlalchemy/future/engine.py,sha256=AgIw6vMsef8W6tynOTkxsjd6o_OQDwGjLdbpoMD8ue8,495
sqlalchemy/inspection.py,sha256=MF-LE358wZDUEl1IH8-Uwt2HI65EsQpQW5o5udHkZwA,5063
sqlalchemy/log.py,sha256=8x9UR3nj0uFm6or6bQF-JWb4fYv2zOeQjG_w-0wOJFA,8607
sqlalchemy/orm/__init__.py,sha256=ZYys5nL3RFUDCMOLFDBrRI52F6er3S1U1OY9TeORuKs,8463
sqlalchemy/orm/__pycache__/__init__.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/_orm_constructors.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/_typing.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/attributes.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/base.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/bulk_persistence.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/clsregistry.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/collections.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/context.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/decl_api.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/decl_base.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/dependency.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/descriptor_props.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/dynamic.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/evaluator.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/events.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/exc.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/identity.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/instrumentation.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/interfaces.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/loading.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/mapped_collection.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/mapper.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/path_registry.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/persistence.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/properties.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/query.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/relationships.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/scoping.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/session.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/state.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/state_changes.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/strategies.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/strategy_options.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/sync.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/unitofwork.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/util.cpython-312.pyc,,
sqlalchemy/orm/__pycache__/writeonly.cpython-312.pyc,,
sqlalchemy/orm/_orm_constructors.py,sha256=c4RMiYKIXzOTjuPIBbyRIzpizYjUBm2sd7k0n1vqb2o,100717
sqlalchemy/orm/_typing.py,sha256=DVBfpHmDVK4x1zxaGJPY2GoTrAsyR6uexv20Lzf1afc,4973
sqlalchemy/orm/attributes.py,sha256=lorOHBJvJJYndOuafWJhHBbQ1pR6FAyimhqz-mErBRQ,92534
sqlalchemy/orm/base.py,sha256=re6A8ooMxLyfCAeQfhBwwxeJQkiH7EtzzOZIVIiTPlw,27466
sqlalchemy/orm/bulk_persistence.py,sha256=gNp2gFsGvV-5NhOPBL51TqKgR3ZRrS43jSwqUF-SwgY,71430
sqlalchemy/orm/clsregistry.py,sha256=IjoDZwWpjG42ji59L4M1EZvjBEoXPZykzENDtKWxU8A,17974
sqlalchemy/orm/collections.py,sha256=WEKuUCRgLhDhJEIBhZ21UrE0pBOyRm2zxD20GvbgA9g,52243
sqlalchemy/orm/context.py,sha256=FMPyw07OA9OXWQ32RQx52AEa2xTLSkqdYgx9R_yN1x0,112955
sqlalchemy/orm/decl_api.py,sha256=_WPKQ_vSE5k2TLtNmkaxxYmvbhZvkRMrrvCeDxdqDQE,63998
sqlalchemy/orm/decl_base.py,sha256=FTHf3bCVlg52KR6JWVEwuG3XjOaGQ5KJMYFYXastGhw,82832
sqlalchemy/orm/dependency.py,sha256=hgjksUWhgbmgHK5GdJdiDCBgDAIGQXIrY-Tj79tbL2k,47631
sqlalchemy/orm/descriptor_props.py,sha256=dR_h4Gvdtpcdp4sj_ZOR4P5Nng2J2vhsvFHouRLlntc,37244
sqlalchemy/orm/dynamic.py,sha256=rWAZ-nfAkREuNjt8e_FRdqYrvHDdbODn1CcfyP8Y18k,9816
sqlalchemy/orm/evaluator.py,sha256=tRETz4dNZ71VsEA8nG0hpefByB-W0zBt02IxcSR5H2g,12353
sqlalchemy/orm/events.py,sha256=1PiGT7JMUWTDAb3X1T79P02BMVDmcWEpatz1FwpLqoA,127777
sqlalchemy/orm/exc.py,sha256=IP40P-wOeXhkYk0YizuTC3wqm6W9cPTaQU08f5MMaQ0,7413
sqlalchemy/orm/identity.py,sha256=jHdCxCpCyda_8mFOfGmN_Pr0XZdKiU-2hFZshlNxbHs,9249
sqlalchemy/orm/instrumentation.py,sha256=M-kZmkUvHUxtf-0mCA8RIM5QmMH1hWlYR_pKMwaidjA,24321
sqlalchemy/orm/interfaces.py,sha256=Hmf1BjbfOarZRgMlruqghR7cgH2xyugA9v5t0x-a-wU,48502
sqlalchemy/orm/loading.py,sha256=9RacpzFOWbuKgPRWHFmyIvD4fYCLAnkpwBFASyQ2CoI,58277
sqlalchemy/orm/mapped_collection.py,sha256=zK3d3iozORzDruBUrAmkVC0RR3Orj5szk-TSQ24xzIU,19682
sqlalchemy/orm/mapper.py,sha256=bfoRzNKKnjF-CDvr2Df7HZC9TepvtuQ49LRz_fW7DGQ,171088
sqlalchemy/orm/path_registry.py,sha256=sJZMv_WPqUpHfQtKWaX3WYFeKBcNJ8C3wOM2mkBGkTE,25920
sqlalchemy/orm/persistence.py,sha256=dzyB2JOXNwQgaCbN8kh0sEz00WFePr48qf8NWVCUZH8,61701
sqlalchemy/orm/properties.py,sha256=eDPFzxYUgdM3uWjHywnb1XW-i0tVKKyx7A2MCD31GQU,29306
sqlalchemy/orm/query.py,sha256=Cf0e94-u1XyoXJoOAmr4iFvtCwNY98kxUYyMPenaWTE,117708
sqlalchemy/orm/relationships.py,sha256=dS5SY0v1MiD7iCNnAQlHaI6prUQhL5EkXT7ijc8FR8E,128644
sqlalchemy/orm/scoping.py,sha256=rJVc7_Lic4V00HZ-UvYFWkVpXqdrMayRmIs4fIwH1UA,78688
sqlalchemy/orm/session.py,sha256=CZJTQ-wPwIy0c3AMFxgJnBgaft6eEf4JzcCLcaaCSjg,195979
sqlalchemy/orm/state.py,sha256=327-F4TG29s6mLC8oWRiO2PuvYIUZzY1MqUPjtUy7M4,37670
sqlalchemy/orm/state_changes.py,sha256=qKYg7NxwrDkuUY3EPygAztym6oAVUFcP2wXn7QD3Mz4,6815
sqlalchemy/orm/strategies.py,sha256=U5EL1FBXOmkIV5HsryIlTvfQfoajYGCnvTbuKBnH0pQ,116224
sqlalchemy/orm/strategy_options.py,sha256=oeDl_rMDNAC_90N7ytsni-psXWAeQMhABQFyKBSmai0,85353
sqlalchemy/orm/sync.py,sha256=g7iZfSge1HgxMk9SKRgUgtHEbpbZ1kP_CBqOIdTOXqc,5779
sqlalchemy/orm/unitofwork.py,sha256=fiVaqcymbDDHRa1NjS90N9Z466nd5pkJOEi1dHO6QLY,27033
sqlalchemy/orm/util.py,sha256=Q0JT2JydyGiNiYT8AVe9B6jOdBRVHSOVDIcWOsXXIUQ,80929
sqlalchemy/orm/writeonly.py,sha256=SYu2sAaHZONk2pW4PmtE871LG-O0P_bjidvKzY1H_zI,22305
sqlalchemy/pool/__init__.py,sha256=qiDdq4r4FFAoDrK6ncugF_i6usi_X1LeJt-CuBHey0s,1804
sqlalchemy/pool/__pycache__/__init__.cpython-312.pyc,,
sqlalchemy/pool/__pycache__/base.cpython-312.pyc,,
sqlalchemy/pool/__pycache__/events.cpython-312.pyc,,
sqlalchemy/pool/__pycache__/impl.cpython-312.pyc,,
sqlalchemy/pool/base.py,sha256=WF4az4ZKuzQGuKeSJeyexaYjmWZUvYdC6KIi8zTGodw,52236
sqlalchemy/pool/events.py,sha256=xGjkIUZl490ZDtCHqnQF9ZCwe2Jv93eGXmnQxftB11E,13147
sqlalchemy/pool/impl.py,sha256=JwpALSkH-pCoO_6oENbkHYY00Jx9nlttyoI61LivRNc,18944
sqlalchemy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
sqlalchemy/schema.py,sha256=dKiWmgHYjcKQ4TiiD6vD0UMmIsD8u0Fsor1M9AAeGUs,3194
sqlalchemy/sql/__init__.py,sha256=UNa9EUiYWoPayf-FzNcwVgQvpsBdInPZfpJesAStN9o,5820
sqlalchemy/sql/__pycache__/__init__.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/_dml_constructors.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/_elements_constructors.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/_orm_types.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/_py_util.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/_selectable_constructors.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/_typing.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/annotation.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/base.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/cache_key.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/coercions.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/compiler.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/crud.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/ddl.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/default_comparator.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/dml.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/elements.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/events.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/expression.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/functions.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/lambdas.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/naming.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/operators.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/roles.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/schema.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/selectable.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/sqltypes.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/traversals.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/type_api.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/util.cpython-312.pyc,,
sqlalchemy/sql/__pycache__/visitors.cpython-312.pyc,,
sqlalchemy/sql/_dml_constructors.py,sha256=YdBJex0MCVACv4q2nl_ii3uhxzwU6aDB8zAsratX5UQ,3867
sqlalchemy/sql/_elements_constructors.py,sha256=1SX6o1ezeB8C9DAa2m0WxmfhM3ji3FeCprXFQkNerNY,63048
sqlalchemy/sql/_orm_types.py,sha256=T-vjcry4C1y0GToFKVxQCnmly_-Zsq4IO4SHN6bvUF4,625
sqlalchemy/sql/_py_util.py,sha256=hiM9ePbRSGs60bAMxPFuJCIC_p9SQ1VzqXGiPchiYwE,2173
sqlalchemy/sql/_selectable_constructors.py,sha256=wjE6HrLm9cR7bxvZXT8sFLUqT6t_J9G1XyQCnYmBDl0,18780
sqlalchemy/sql/_typing.py,sha256=oqwrYHVMtK-AuKGH9c4SgfiOEJUt5vjkzSEzzscMHkM,12771
sqlalchemy/sql/annotation.py,sha256=aqbbVz9kfbCT3_66CZ9GEirVN197Cukoqt8rq48FgkQ,18245
sqlalchemy/sql/base.py,sha256=M1b-Tg49ikUW2mnZv0aI38oASG6dgeo4jBNWDgJgAg8,73925
sqlalchemy/sql/cache_key.py,sha256=0Db8mR8IrpBgdzXs4TGTt98LOpL3c7KABd72MAPKUQQ,33668
sqlalchemy/sql/coercions.py,sha256=KjrVc2ks6cx_o6-_Zpu6uPuNGjJy2xvFzXy8z5oshQg,40628
sqlalchemy/sql/compiler.py,sha256=hrTptbOKIgVIHapywj4Lk5OMwpXvHS-KGg3odFwlo-I,274687
sqlalchemy/sql/crud.py,sha256=HBX4QPtW_PYYJmIKfNr-wE8IdEr963N24WXzFBUZOo0,56514
sqlalchemy/sql/ddl.py,sha256=CIqMilCKfuQnF0lrZsQdTxgrbXqcTauKr0Ojzj77PFQ,45602
sqlalchemy/sql/default_comparator.py,sha256=utXWsZVGEjflhFfCT4ywa6RnhORc1Rryo87Hga71Rps,16707
sqlalchemy/sql/dml.py,sha256=pn0Lm1ofC5qVZzwGWFW73lPCiNba8OsTeemurJgwRyg,65614
sqlalchemy/sql/elements.py,sha256=YfccXzQc9DlgF8q15kDf-zKBUY_vpIe0FGaVDBPoic4,176544
sqlalchemy/sql/events.py,sha256=iC_Q1Htm1Aobt5tOYxWfHHqNpoytrULORmUKcusH_-E,18290
sqlalchemy/sql/expression.py,sha256=VMX-dLpsZYnVRJpYNDozDUgaj7iQ0HuewUKVefD57PE,7586
sqlalchemy/sql/functions.py,sha256=kMMYplvuIHFAPwxBI03SizwaLcYEHzysecWk-R1V-JM,63762
sqlalchemy/sql/lambdas.py,sha256=DP0Qz7Ypo8QhzMwygGHYgRhwJMx-rNezO1euouH3iYU,49292
sqlalchemy/sql/naming.py,sha256=ZHs1qSV3ou8TYmZ92uvU3sfdklUQlIz4uhe330n05SU,6858
sqlalchemy/sql/operators.py,sha256=himArRqBzrljob3Zfhi_ZS-Jleg1u6YFp0g3d7Co6IM,76106
sqlalchemy/sql/roles.py,sha256=pOsVn_OZD7mF2gJByHf24Rjopt0_Hu3dUCEOK5t4KS8,7662
sqlalchemy/sql/schema.py,sha256=iFleWHkxi-3mKGiK_N1TzUqxnNwOpypB4bWDuAVQe8c,229717
sqlalchemy/sql/selectable.py,sha256=cgyV0AsPy4CXAFdhMiTCkbgaHiFilW9sclzxlHJKH3o,236460
sqlalchemy/sql/sqltypes.py,sha256=fajBVE_CCJykrQpOOnb8_HFOKCSoUF48AxljJymvGk4,127330
sqlalchemy/sql/traversals.py,sha256=3ScTC1fh1-y8Y478h_2Azmd2xdQdWPWkDve4YgrwMf8,33664
sqlalchemy/sql/type_api.py,sha256=q_FieFRALHiRkhy5Bj-cVgFHa7DXF1dP23FaRRYKeho,83717
sqlalchemy/sql/util.py,sha256=qGHQF-tPCj-m1FBerzT7weCanGcXU7dK5m-W7NHio-4,48077
sqlalchemy/sql/visitors.py,sha256=71wdVvhhZL4nJvVwFAs6ssaW-qZgNRSmKjpAcOzF_TA,36317
sqlalchemy/testing/__init__.py,sha256=zgitAYzsCWT_U48ZiifXHHLJFo8nZBYmI-5TueA4_lE,3160
sqlalchemy/testing/__pycache__/__init__.cpython-312.pyc,,
sqlalchemy/testing/__pycache__/assertions.cpython-312.pyc,,
sqlalchemy/testing/__pycache__/assertsql.cpython-312.pyc,,
sqlalchemy/testing/__pycache__/asyncio.cpython-312.pyc,,
sqlalchemy/testing/__pycache__/config.cpython-312.pyc,,
sqlalchemy/testing/__pycache__/engines.cpython-312.pyc,,
sqlalchemy/testing/__pycache__/entities.cpython-312.pyc,,
sqlalchemy/testing/__pycache__/exclusions.cpython-312.pyc,,
sqlalchemy/testing/__pycache__/pickleable.cpython-312.pyc,,
sqlalchemy/testing/__pycache__/profiling.cpython-312.pyc,,
sqlalchemy/testing/__pycache__/provision.cpython-312.pyc,,
sqlalchemy/testing/__pycache__/requirements.cpython-312.pyc,,
sqlalchemy/testing/__pycache__/schema.cpython-312.pyc,,
sqlalchemy/testing/__pycache__/util.cpython-312.pyc,,
sqlalchemy/testing/__pycache__/warnings.cpython-312.pyc,,
sqlalchemy/testing/assertions.py,sha256=gL0rA7CCZJbcVgvWOPV91tTZTRwQc1_Ta0-ykBn83Ew,31439
sqlalchemy/testing/assertsql.py,sha256=IgQG7l94WaiRP8nTbilJh1ZHZl125g7GPq-S5kmQZN0,16817
sqlalchemy/testing/asyncio.py,sha256=kM8uuOqDBagZF0r9xvGmsiirUVLUQ_KBzjUFU67W-b8,3830
sqlalchemy/testing/config.py,sha256=AqyH1qub_gDqX0BvlL-JBQe7N-t2wo8655FtwblUNOY,12090
sqlalchemy/testing/engines.py,sha256=HFJceEBD3Q_TTFQMTtIV5wGWO_a7oUgoKtUF_z636SM,13481
sqlalchemy/testing/entities.py,sha256=IphFegPKbff3Un47jY6bi7_MQXy6qkx_50jX2tHZJR4,3354
sqlalchemy/testing/exclusions.py,sha256=T8B01hmm8WVs-EKcUOQRzabahPqblWJfOidi6bHJ6GA,12460
sqlalchemy/testing/fixtures/__init__.py,sha256=dMClrIoxqlYIFpk2ia4RZpkbfxsS_3EBigr9QsPJ66g,1198
sqlalchemy/testing/fixtures/__pycache__/__init__.cpython-312.pyc,,
sqlalchemy/testing/fixtures/__pycache__/base.cpython-312.pyc,,
sqlalchemy/testing/fixtures/__pycache__/mypy.cpython-312.pyc,,
sqlalchemy/testing/fixtures/__pycache__/orm.cpython-312.pyc,,
sqlalchemy/testing/fixtures/__pycache__/sql.cpython-312.pyc,,
sqlalchemy/testing/fixtures/base.py,sha256=9r_J2ksiTzClpUxW0TczICHrWR7Ny8PV8IsBz6TsGFI,12256
sqlalchemy/testing/fixtures/mypy.py,sha256=gdxiwNFIzDlNGSOdvM3gbwDceVCC9t8oM5kKbwyhGBk,11973
sqlalchemy/testing/fixtures/orm.py,sha256=8EFbnaBbXX_Bf4FcCzBUaAHgyVpsLGBHX16SGLqE3Fg,6095
sqlalchemy/testing/fixtures/sql.py,sha256=KZMjco9_3dsuspmkew5Ejp88Wlr9PsSBB1qeJGFxQAk,15900
sqlalchemy/testing/pickleable.py,sha256=U9mIqk-zaxq9Xfy7HErP7UrKgTov-A3QFnhZh-NiOjI,2833
sqlalchemy/testing/plugin/__init__.py,sha256=79F--BIY_NTBzVRIlJGgAY5LNJJ3cD19XvrAo4X0W9A,247
sqlalchemy/testing/plugin/__pycache__/__init__.cpython-312.pyc,,
sqlalchemy/testing/plugin/__pycache__/bootstrap.cpython-312.pyc,,
sqlalchemy/testing/plugin/__pycache__/plugin_base.cpython-312.pyc,,
sqlalchemy/testing/plugin/__pycache__/pytestplugin.cpython-312.pyc,,
sqlalchemy/testing/plugin/bootstrap.py,sha256=oYScMbEW4pCnWlPEAq1insFruCXFQeEVBwo__i4McpU,1685
sqlalchemy/testing/plugin/plugin_base.py,sha256=BgNzWNEmgpK4CwhyblQQKnH-7FDKVi_Uul5vw8fFjBU,21578
sqlalchemy/testing/plugin/pytestplugin.py,sha256=6jkQHH2VQMD75k2As9CuWXmEy9jrscoFRhCNg6-PaTw,27656
sqlalchemy/testing/profiling.py,sha256=PbuPhRFbauFilUONeY3tV_Y_5lBkD7iCa8VVyH2Sk9Y,10148
sqlalchemy/testing/provision.py,sha256=3qFor_sN1FFlS7odUGkKqLUxGmQZC9XM67I9vQ_zeXo,14626
sqlalchemy/testing/requirements.py,sha256=Z__o-1Rj9B7dI8E_l3qsKTvsg0rK198vB0A1p7A5dcM,52832
sqlalchemy/testing/schema.py,sha256=lr4GkGrGwagaHMuSGzWdzkMaj3HnS7dgfLLWfxt__-U,6513
sqlalchemy/testing/suite/__init__.py,sha256=Y5DRNG0Yl1u3ypt9zVF0Z9suPZeuO_UQGLl-wRgvTjU,722
sqlalchemy/testing/suite/__pycache__/__init__.cpython-312.pyc,,
sqlalchemy/testing/suite/__pycache__/test_cte.cpython-312.pyc,,
sqlalchemy/testing/suite/__pycache__/test_ddl.cpython-312.pyc,,
sqlalchemy/testing/suite/__pycache__/test_deprecations.cpython-312.pyc,,
sqlalchemy/testing/suite/__pycache__/test_dialect.cpython-312.pyc,,
sqlalchemy/testing/suite/__pycache__/test_insert.cpython-312.pyc,,
sqlalchemy/testing/suite/__pycache__/test_reflection.cpython-312.pyc,,
sqlalchemy/testing/suite/__pycache__/test_results.cpython-312.pyc,,
sqlalchemy/testing/suite/__pycache__/test_rowcount.cpython-312.pyc,,
sqlalchemy/testing/suite/__pycache__/test_select.cpython-312.pyc,,
sqlalchemy/testing/suite/__pycache__/test_sequence.cpython-312.pyc,,
sqlalchemy/testing/suite/__pycache__/test_types.cpython-312.pyc,,
sqlalchemy/testing/suite/__pycache__/test_unicode_ddl.cpython-312.pyc,,
sqlalchemy/testing/suite/__pycache__/test_update_delete.cpython-312.pyc,,
sqlalchemy/testing/suite/test_cte.py,sha256=6zBC3W2OwX1Xs-HedzchcKN2S7EaLNkgkvV_JSZ_Pq0,6451
sqlalchemy/testing/suite/test_ddl.py,sha256=1Npkf0C_4UNxphthAGjG078n0vPEgnSIHpDu5MfokxQ,12031
sqlalchemy/testing/suite/test_deprecations.py,sha256=BcJxZTcjYqeOAENVElCg3hVvU6fkGEW3KGBMfnW8bng,5337
sqlalchemy/testing/suite/test_dialect.py,sha256=EH4ZQWbnGdtjmx5amZtTyhYmrkXJCvW1SQoLahoE7uk,22923
sqlalchemy/testing/suite/test_insert.py,sha256=9azifj6-OCD7s8h_tAO1uPw100ibQv8YoKc_VA3hn3c,18824
sqlalchemy/testing/suite/test_reflection.py,sha256=7sML8-owubSQeEM7Ve6LbnB8uIVlNV00WWepKwII2a8,109648
sqlalchemy/testing/suite/test_results.py,sha256=X720GafdA4p75SOGS93j-dXkt6QDEnnJbU2bh18VCcg,16914
sqlalchemy/testing/suite/test_rowcount.py,sha256=3KDTlRgjpQ1OVfp__1cv8Hvq4CsDKzmrhJQ_WIJWoJg,7900
sqlalchemy/testing/suite/test_select.py,sha256=ulRZQJlzkwwcewEyisuBEXVWFR0Wshz9MEDxYYiYLwQ,61732
sqlalchemy/testing/suite/test_sequence.py,sha256=66bCoy4xo99GBSaX6Hxb88foANAykLGRz1YEKbvpfuA,9923
sqlalchemy/testing/suite/test_types.py,sha256=K4MGHvnTtgqeksoQOBCZRVQYC7HoYO6Z6rVt5vj2t9o,67805
sqlalchemy/testing/suite/test_unicode_ddl.py,sha256=c3_eIxLyORuSOhNDP0jWKxPyUf3SwMFpdalxtquwqlM,6141
sqlalchemy/testing/suite/test_update_delete.py,sha256=yTiM2unnfOK9rK8ZkqeTTU_MkT-RsKFLmdYliniZfAY,3994
sqlalchemy/testing/util.py,sha256=qldXKw8gRJ4I2x3uXsBssYMqwatmcMFMTOveRQCmfDU,14469
sqlalchemy/testing/warnings.py,sha256=fJ-QJUY2zY2PPxZJKv9medW-BKKbCNbA4Ns_V3YwFXM,1546
sqlalchemy/types.py,sha256=cQFM-hFRmaf1GErun1qqgEs6QxufvzMuwKqj9tuMPpE,3168
sqlalchemy/util/__init__.py,sha256=B3bedg-LSQEscwqgmYYU-VENUX8_zAE3q9vb7tkfJNY,8277
sqlalchemy/util/__pycache__/__init__.cpython-312.pyc,,
sqlalchemy/util/__pycache__/_collections.cpython-312.pyc,,
sqlalchemy/util/__pycache__/_concurrency_py3k.cpython-312.pyc,,
sqlalchemy/util/__pycache__/_has_cy.cpython-312.pyc,,
sqlalchemy/util/__pycache__/_py_collections.cpython-312.pyc,,
sqlalchemy/util/__pycache__/compat.cpython-312.pyc,,
sqlalchemy/util/__pycache__/concurrency.cpython-312.pyc,,
sqlalchemy/util/__pycache__/deprecations.cpython-312.pyc,,
sqlalchemy/util/__pycache__/langhelpers.cpython-312.pyc,,
sqlalchemy/util/__pycache__/preloaded.cpython-312.pyc,,
sqlalchemy/util/__pycache__/queue.cpython-312.pyc,,
sqlalchemy/util/__pycache__/tool_support.cpython-312.pyc,,
sqlalchemy/util/__pycache__/topological.cpython-312.pyc,,
sqlalchemy/util/__pycache__/typing.cpython-312.pyc,,
sqlalchemy/util/_collections.py,sha256=aZoSAVOXnHBoYEsxDOi0O9odg9wqLbGb7PGjaWQKiyY,20078
sqlalchemy/util/_concurrency_py3k.py,sha256=zb0Bow2Y_QjTdaACEviBEEaFvqDuVvpJfmwCjaw8xNE,9170
sqlalchemy/util/_has_cy.py,sha256=wCQmeSjT3jaH_oxfCEtGk-1g0gbSpt5MCK5UcWdMWqk,1247
sqlalchemy/util/_py_collections.py,sha256=U6L5AoyLdgSv7cdqB4xxQbw1rpeJjyOZVXffgxgga8I,16714
sqlalchemy/util/compat.py,sha256=fJWqZVkW7qPY2l0DxK-7fHKjyp7b-wa-5wOlmuZlick,8724
sqlalchemy/util/concurrency.py,sha256=9lT_cMoO1fZNdY8QTUZ22oeSf-L5I-79Ke7chcBNPA0,3304
sqlalchemy/util/deprecations.py,sha256=YBwvvYhSB8LhasIZRKvg_-WNoVhPUcaYI1ZrnjDn868,11971
sqlalchemy/util/langhelpers.py,sha256=uIK3szZuq9aMnO-vEpSlNekNWv4I-E391e56bkTnUm0,65090
sqlalchemy/util/preloaded.py,sha256=az7NmLJLsqs0mtM9uBkIu10-841RYDq8wOyqJ7xXvqE,5904
sqlalchemy/util/queue.py,sha256=CaeSEaYZ57YwtmLdNdOIjT5PK_LCuwMFiO0mpp39ybM,10185
sqlalchemy/util/tool_support.py,sha256=9braZyidaiNrZVsWtGmkSmus50-byhuYrlAqvhjcmnA,6135
sqlalchemy/util/topological.py,sha256=N3M3Le7KzGHCmqPGg0ZBqixTDGwmFLhOZvBtc4rHL_g,3458
sqlalchemy/util/typing.py,sha256=lFcGo1dJbZIZ9drAnvef-PzP0cX4LMxMSwgk3lJBb0g,18182

View File

@@ -0,0 +1,6 @@
Wheel-Version: 1.0
Generator: setuptools (75.1.0)
Root-Is-Purelib: false
Tag: cp312-cp312-manylinux_2_17_x86_64
Tag: cp312-cp312-manylinux2014_x86_64

View File

@@ -0,0 +1,33 @@
# This is a stub package designed to roughly emulate the _yaml
# extension module, which previously existed as a standalone module
# and has been moved into the `yaml` package namespace.
# It does not perfectly mimic its old counterpart, but should get
# close enough for anyone who's relying on it even when they shouldn't.
import yaml
# in some circumstances, the yaml module we imoprted may be from a different version, so we need
# to tread carefully when poking at it here (it may not have the attributes we expect)
if not getattr(yaml, '__with_libyaml__', False):
from sys import version_info
exc = ModuleNotFoundError if version_info >= (3, 6) else ImportError
raise exc("No module named '_yaml'")
else:
from yaml._yaml import *
import warnings
warnings.warn(
'The _yaml extension module is now located at yaml._yaml'
' and its location is subject to change. To use the'
' LibYAML-based parser and emitter, import from `yaml`:'
' `from yaml import CLoader as Loader, CDumper as Dumper`.',
DeprecationWarning
)
del warnings
# Don't `del yaml` here because yaml is actually an existing
# namespace member of _yaml.
__name__ = '_yaml'
# If the module is top-level (i.e. not a part of any specific package)
# then the attribute should be set to ''.
# https://docs.python.org/3.8/library/types.html
__package__ = ''

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Amethyst Reese
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,122 @@
Metadata-Version: 2.1
Name: aiosqlite
Version: 0.20.0
Summary: asyncio bridge to the standard sqlite3 module
Author-email: Amethyst Reese <amy@n7.gg>
Requires-Python: >=3.8
Description-Content-Type: text/x-rst
Classifier: Development Status :: 5 - Production/Stable
Classifier: Framework :: AsyncIO
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Topic :: Software Development :: Libraries
Requires-Dist: typing_extensions >= 4.0
Requires-Dist: attribution==1.7.0 ; extra == "dev"
Requires-Dist: black==24.2.0 ; extra == "dev"
Requires-Dist: coverage[toml]==7.4.1 ; extra == "dev"
Requires-Dist: flake8==7.0.0 ; extra == "dev"
Requires-Dist: flake8-bugbear==24.2.6 ; extra == "dev"
Requires-Dist: flit==3.9.0 ; extra == "dev"
Requires-Dist: mypy==1.8.0 ; extra == "dev"
Requires-Dist: ufmt==2.3.0 ; extra == "dev"
Requires-Dist: usort==1.0.8.post1 ; extra == "dev"
Requires-Dist: sphinx==7.2.6 ; extra == "docs"
Requires-Dist: sphinx-mdinclude==0.5.3 ; extra == "docs"
Project-URL: Documentation, https://aiosqlite.omnilib.dev
Project-URL: Github, https://github.com/omnilib/aiosqlite
Provides-Extra: dev
Provides-Extra: docs
aiosqlite\: Sqlite for AsyncIO
==============================
.. image:: https://readthedocs.org/projects/aiosqlite/badge/?version=latest
:target: https://aiosqlite.omnilib.dev/en/latest/?badge=latest
:alt: Documentation Status
.. image:: https://img.shields.io/pypi/v/aiosqlite.svg
:target: https://pypi.org/project/aiosqlite
:alt: PyPI Release
.. image:: https://img.shields.io/badge/change-log-blue
:target: https://github.com/omnilib/aiosqlite/blob/master/CHANGELOG.md
:alt: Changelog
.. image:: https://img.shields.io/pypi/l/aiosqlite.svg
:target: https://github.com/omnilib/aiosqlite/blob/master/LICENSE
:alt: MIT Licensed
aiosqlite provides a friendly, async interface to sqlite databases.
It replicates the standard ``sqlite3`` module, but with async versions
of all the standard connection and cursor methods, plus context managers for
automatically closing connections and cursors:
.. code-block:: python
async with aiosqlite.connect(...) as db:
await db.execute("INSERT INTO some_table ...")
await db.commit()
async with db.execute("SELECT * FROM some_table") as cursor:
async for row in cursor:
...
It can also be used in the traditional, procedural manner:
.. code-block:: python
db = await aiosqlite.connect(...)
cursor = await db.execute('SELECT * FROM some_table')
row = await cursor.fetchone()
rows = await cursor.fetchall()
await cursor.close()
await db.close()
aiosqlite also replicates most of the advanced features of ``sqlite3``:
.. code-block:: python
async with aiosqlite.connect(...) as db:
db.row_factory = aiosqlite.Row
async with db.execute('SELECT * FROM some_table') as cursor:
async for row in cursor:
value = row['column']
await db.execute('INSERT INTO foo some_table')
assert db.total_changes > 0
Install
-------
aiosqlite is compatible with Python 3.8 and newer.
You can install it from PyPI:
.. code-block:: console
$ pip install aiosqlite
Details
-------
aiosqlite allows interaction with SQLite databases on the main AsyncIO event
loop without blocking execution of other coroutines while waiting for queries
or data fetches. It does this by using a single, shared thread per connection.
This thread executes all actions within a shared request queue to prevent
overlapping actions.
Connection objects are proxies to the real connections, contain the shared
execution thread, and provide context managers to handle automatically closing
connections. Cursors are similarly proxies to the real cursors, and provide
async iterators to query results.
License
-------
aiosqlite is copyright `Amethyst Reese <https://noswap.com>`_, and licensed under the
MIT license. I am providing code in this repository to you under an open source
license. This is my personal repository; the license you receive to my code
is from me and not from my employer. See the `LICENSE`_ file for details.
.. _LICENSE: https://github.com/omnilib/aiosqlite/blob/master/LICENSE

View File

@@ -0,0 +1,27 @@
aiosqlite-0.20.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
aiosqlite-0.20.0.dist-info/LICENSE,sha256=qwwXHcPvi_MlqEu3fYVUIfJhEzXd9uCIFrKSLE7cD3Y,1071
aiosqlite-0.20.0.dist-info/METADATA,sha256=Ec4xgHlepuHQhJ8Ldg7EkveV2Aj8wdc8P6gaUzfNU28,4275
aiosqlite-0.20.0.dist-info/RECORD,,
aiosqlite-0.20.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
aiosqlite-0.20.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
aiosqlite/__init__.py,sha256=JMIfUTUQRPkz3IrNFp3MK3uIMfGkMauUKZ3TS1vnqqk,893
aiosqlite/__pycache__/__init__.cpython-312.pyc,,
aiosqlite/__pycache__/__version__.cpython-312.pyc,,
aiosqlite/__pycache__/context.cpython-312.pyc,,
aiosqlite/__pycache__/core.cpython-312.pyc,,
aiosqlite/__pycache__/cursor.cpython-312.pyc,,
aiosqlite/__version__.py,sha256=6eee2XXMX-6B4aIDDNSY-QHv9gvpf7vhSTbYTyDebNU,157
aiosqlite/context.py,sha256=d78NqvrUgj3UQFFbwpJM0S1TjNtJJ5VpQ77pq3j3OIk,1372
aiosqlite/core.py,sha256=37wORBXtJ4xhDdqOVvqppDNM4XeNYD6RHslVkzMCBYI,12226
aiosqlite/cursor.py,sha256=XzdHbUCy76Ot53r5cAHvepU6LyXxNSNR2Oh9L1a4M6s,3504
aiosqlite/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
aiosqlite/tests/__init__.py,sha256=nKLBhR8SLx2dkw4UL052QKD7EzC9ctagfSJ9MpsDPrY,95
aiosqlite/tests/__main__.py,sha256=V3sH21pONg0y2-WN7rkfvgjf8zO-lS1wFyINq5hTdpA,167
aiosqlite/tests/__pycache__/__init__.cpython-312.pyc,,
aiosqlite/tests/__pycache__/__main__.cpython-312.pyc,,
aiosqlite/tests/__pycache__/helpers.cpython-312.pyc,,
aiosqlite/tests/__pycache__/perf.cpython-312.pyc,,
aiosqlite/tests/__pycache__/smoke.cpython-312.pyc,,
aiosqlite/tests/helpers.py,sha256=ghmZrf_nEfjkuRpZkCH9Pmg2ZnC19c2Leiq9nXqVX_g,727
aiosqlite/tests/perf.py,sha256=pBCOKkTLh0j4cz7ZWe3WNxsVmdKTKAw0VWN_K-YwRmc,6593
aiosqlite/tests/smoke.py,sha256=9B-6Wo4rLP9rfdyRxG_QY2JAJtq7fDTJoT8gjeCkWi4,16580

View File

@@ -0,0 +1,4 @@
Wheel-Version: 1.0
Generator: flit 3.9.0
Root-Is-Purelib: true
Tag: py3-none-any

View File

@@ -0,0 +1,44 @@
# Copyright 2022 Amethyst Reese
# Licensed under the MIT license
"""asyncio bridge to the standard sqlite3 module"""
from sqlite3 import ( # pylint: disable=redefined-builtin
DatabaseError,
Error,
IntegrityError,
NotSupportedError,
OperationalError,
paramstyle,
ProgrammingError,
register_adapter,
register_converter,
Row,
sqlite_version,
sqlite_version_info,
Warning,
)
__author__ = "Amethyst Reese"
from .__version__ import __version__
from .core import connect, Connection, Cursor
__all__ = [
"__version__",
"paramstyle",
"register_adapter",
"register_converter",
"sqlite_version",
"sqlite_version_info",
"connect",
"Connection",
"Cursor",
"Row",
"Warning",
"Error",
"DatabaseError",
"IntegrityError",
"ProgrammingError",
"OperationalError",
"NotSupportedError",
]

View File

@@ -0,0 +1,7 @@
"""
This file is automatically generated by attribution.
Do not edit manually. Get more info at https://attribution.omnilib.dev
"""
__version__ = "0.20.0"

View File

@@ -0,0 +1,54 @@
# Copyright 2018
# Licensed under the MIT license
from functools import wraps
from typing import Any, AsyncContextManager, Callable, Coroutine, Generator, TypeVar
from .cursor import Cursor
_T = TypeVar("_T")
class Result(AsyncContextManager[_T], Coroutine[Any, Any, _T]):
__slots__ = ("_coro", "_obj")
def __init__(self, coro: Coroutine[Any, Any, _T]):
self._coro = coro
self._obj: _T
def send(self, value) -> None:
return self._coro.send(value)
def throw(self, typ, val=None, tb=None) -> None:
if val is None:
return self._coro.throw(typ)
if tb is None:
return self._coro.throw(typ, val)
return self._coro.throw(typ, val, tb)
def close(self) -> None:
return self._coro.close()
def __await__(self) -> Generator[Any, None, _T]:
return self._coro.__await__()
async def __aenter__(self) -> _T:
self._obj = await self._coro
return self._obj
async def __aexit__(self, exc_type, exc, tb) -> None:
if isinstance(self._obj, Cursor):
await self._obj.close()
def contextmanager(
method: Callable[..., Coroutine[Any, Any, _T]]
) -> Callable[..., Result[_T]]:
@wraps(method)
def wrapper(self, *args, **kwargs) -> Result[_T]:
return Result(method(self, *args, **kwargs))
return wrapper

View File

@@ -0,0 +1,394 @@
# Copyright 2022 Amethyst Reese
# Licensed under the MIT license
"""
Core implementation of aiosqlite proxies
"""
import asyncio
import logging
import sqlite3
from functools import partial
from pathlib import Path
from queue import Empty, Queue, SimpleQueue
from threading import Thread
from typing import (
Any,
AsyncIterator,
Callable,
Generator,
Iterable,
Literal,
Optional,
Tuple,
Type,
Union,
)
from warnings import warn
from .context import contextmanager
from .cursor import Cursor
__all__ = ["connect", "Connection", "Cursor"]
LOG = logging.getLogger("aiosqlite")
IsolationLevel = Optional[Literal["DEFERRED", "IMMEDIATE", "EXCLUSIVE"]]
def set_result(fut: asyncio.Future, result: Any) -> None:
"""Set the result of a future if it hasn't been set already."""
if not fut.done():
fut.set_result(result)
def set_exception(fut: asyncio.Future, e: BaseException) -> None:
"""Set the exception of a future if it hasn't been set already."""
if not fut.done():
fut.set_exception(e)
_STOP_RUNNING_SENTINEL = object()
class Connection(Thread):
def __init__(
self,
connector: Callable[[], sqlite3.Connection],
iter_chunk_size: int,
loop: Optional[asyncio.AbstractEventLoop] = None,
) -> None:
super().__init__()
self._running = True
self._connection: Optional[sqlite3.Connection] = None
self._connector = connector
self._tx: SimpleQueue[Tuple[asyncio.Future, Callable[[], Any]]] = SimpleQueue()
self._iter_chunk_size = iter_chunk_size
if loop is not None:
warn(
"aiosqlite.Connection no longer uses the `loop` parameter",
DeprecationWarning,
)
def _stop_running(self):
self._running = False
# PEP 661 is not accepted yet, so we cannot type a sentinel
self._tx.put_nowait(_STOP_RUNNING_SENTINEL) # type: ignore[arg-type]
@property
def _conn(self) -> sqlite3.Connection:
if self._connection is None:
raise ValueError("no active connection")
return self._connection
def _execute_insert(self, sql: str, parameters: Any) -> Optional[sqlite3.Row]:
cursor = self._conn.execute(sql, parameters)
cursor.execute("SELECT last_insert_rowid()")
return cursor.fetchone()
def _execute_fetchall(self, sql: str, parameters: Any) -> Iterable[sqlite3.Row]:
cursor = self._conn.execute(sql, parameters)
return cursor.fetchall()
def run(self) -> None:
"""
Execute function calls on a separate thread.
:meta private:
"""
while True:
# Continues running until all queue items are processed,
# even after connection is closed (so we can finalize all
# futures)
tx_item = self._tx.get()
if tx_item is _STOP_RUNNING_SENTINEL:
break
future, function = tx_item
try:
LOG.debug("executing %s", function)
result = function()
LOG.debug("operation %s completed", function)
future.get_loop().call_soon_threadsafe(set_result, future, result)
except BaseException as e: # noqa B036
LOG.debug("returning exception %s", e)
future.get_loop().call_soon_threadsafe(set_exception, future, e)
async def _execute(self, fn, *args, **kwargs):
"""Queue a function with the given arguments for execution."""
if not self._running or not self._connection:
raise ValueError("Connection closed")
function = partial(fn, *args, **kwargs)
future = asyncio.get_event_loop().create_future()
self._tx.put_nowait((future, function))
return await future
async def _connect(self) -> "Connection":
"""Connect to the actual sqlite database."""
if self._connection is None:
try:
future = asyncio.get_event_loop().create_future()
self._tx.put_nowait((future, self._connector))
self._connection = await future
except Exception:
self._stop_running()
self._connection = None
raise
return self
def __await__(self) -> Generator[Any, None, "Connection"]:
self.start()
return self._connect().__await__()
async def __aenter__(self) -> "Connection":
return await self
async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
await self.close()
@contextmanager
async def cursor(self) -> Cursor:
"""Create an aiosqlite cursor wrapping a sqlite3 cursor object."""
return Cursor(self, await self._execute(self._conn.cursor))
async def commit(self) -> None:
"""Commit the current transaction."""
await self._execute(self._conn.commit)
async def rollback(self) -> None:
"""Roll back the current transaction."""
await self._execute(self._conn.rollback)
async def close(self) -> None:
"""Complete queued queries/cursors and close the connection."""
if self._connection is None:
return
try:
await self._execute(self._conn.close)
except Exception:
LOG.info("exception occurred while closing connection")
raise
finally:
self._stop_running()
self._connection = None
@contextmanager
async def execute(
self, sql: str, parameters: Optional[Iterable[Any]] = None
) -> Cursor:
"""Helper to create a cursor and execute the given query."""
if parameters is None:
parameters = []
cursor = await self._execute(self._conn.execute, sql, parameters)
return Cursor(self, cursor)
@contextmanager
async def execute_insert(
self, sql: str, parameters: Optional[Iterable[Any]] = None
) -> Optional[sqlite3.Row]:
"""Helper to insert and get the last_insert_rowid."""
if parameters is None:
parameters = []
return await self._execute(self._execute_insert, sql, parameters)
@contextmanager
async def execute_fetchall(
self, sql: str, parameters: Optional[Iterable[Any]] = None
) -> Iterable[sqlite3.Row]:
"""Helper to execute a query and return all the data."""
if parameters is None:
parameters = []
return await self._execute(self._execute_fetchall, sql, parameters)
@contextmanager
async def executemany(
self, sql: str, parameters: Iterable[Iterable[Any]]
) -> Cursor:
"""Helper to create a cursor and execute the given multiquery."""
cursor = await self._execute(self._conn.executemany, sql, parameters)
return Cursor(self, cursor)
@contextmanager
async def executescript(self, sql_script: str) -> Cursor:
"""Helper to create a cursor and execute a user script."""
cursor = await self._execute(self._conn.executescript, sql_script)
return Cursor(self, cursor)
async def interrupt(self) -> None:
"""Interrupt pending queries."""
return self._conn.interrupt()
async def create_function(
self, name: str, num_params: int, func: Callable, deterministic: bool = False
) -> None:
"""
Create user-defined function that can be later used
within SQL statements. Must be run within the same thread
that query executions take place so instead of executing directly
against the connection, we defer this to `run` function.
If ``deterministic`` is true, the created function is marked as deterministic,
which allows SQLite to perform additional optimizations. This flag is supported
by SQLite 3.8.3 or higher, ``NotSupportedError`` will be raised if used with
older versions.
"""
await self._execute(
self._conn.create_function,
name,
num_params,
func,
deterministic=deterministic,
)
@property
def in_transaction(self) -> bool:
return self._conn.in_transaction
@property
def isolation_level(self) -> Optional[str]:
return self._conn.isolation_level
@isolation_level.setter
def isolation_level(self, value: IsolationLevel) -> None:
self._conn.isolation_level = value
@property
def row_factory(self) -> Optional[Type]:
return self._conn.row_factory
@row_factory.setter
def row_factory(self, factory: Optional[Type]) -> None:
self._conn.row_factory = factory
@property
def text_factory(self) -> Callable[[bytes], Any]:
return self._conn.text_factory
@text_factory.setter
def text_factory(self, factory: Callable[[bytes], Any]) -> None:
self._conn.text_factory = factory
@property
def total_changes(self) -> int:
return self._conn.total_changes
async def enable_load_extension(self, value: bool) -> None:
await self._execute(self._conn.enable_load_extension, value) # type: ignore
async def load_extension(self, path: str):
await self._execute(self._conn.load_extension, path) # type: ignore
async def set_progress_handler(
self, handler: Callable[[], Optional[int]], n: int
) -> None:
await self._execute(self._conn.set_progress_handler, handler, n)
async def set_trace_callback(self, handler: Callable) -> None:
await self._execute(self._conn.set_trace_callback, handler)
async def iterdump(self) -> AsyncIterator[str]:
"""
Return an async iterator to dump the database in SQL text format.
Example::
async for line in db.iterdump():
...
"""
dump_queue: Queue = Queue()
def dumper():
try:
for line in self._conn.iterdump():
dump_queue.put_nowait(line)
dump_queue.put_nowait(None)
except Exception:
LOG.exception("exception while dumping db")
dump_queue.put_nowait(None)
raise
fut = self._execute(dumper)
task = asyncio.ensure_future(fut)
while True:
try:
line: Optional[str] = dump_queue.get_nowait()
if line is None:
break
yield line
except Empty:
if task.done():
LOG.warning("iterdump completed unexpectedly")
break
await asyncio.sleep(0.01)
await task
async def backup(
self,
target: Union["Connection", sqlite3.Connection],
*,
pages: int = 0,
progress: Optional[Callable[[int, int, int], None]] = None,
name: str = "main",
sleep: float = 0.250,
) -> None:
"""
Make a backup of the current database to the target database.
Takes either a standard sqlite3 or aiosqlite Connection object as the target.
"""
if isinstance(target, Connection):
target = target._conn
await self._execute(
self._conn.backup,
target,
pages=pages,
progress=progress,
name=name,
sleep=sleep,
)
def connect(
database: Union[str, Path],
*,
iter_chunk_size=64,
loop: Optional[asyncio.AbstractEventLoop] = None,
**kwargs: Any,
) -> Connection:
"""Create and return a connection proxy to the sqlite database."""
if loop is not None:
warn(
"aiosqlite.connect() no longer uses the `loop` parameter",
DeprecationWarning,
)
def connector() -> sqlite3.Connection:
if isinstance(database, str):
loc = database
elif isinstance(database, bytes):
loc = database.decode("utf-8")
else:
loc = str(database)
return sqlite3.connect(loc, **kwargs)
return Connection(connector, iter_chunk_size)

View File

@@ -0,0 +1,118 @@
# Copyright 2022 Amethyst Reese
# Licensed under the MIT license
import sqlite3
from typing import (
Any,
AsyncIterator,
Callable,
Iterable,
Optional,
Tuple,
Type,
TYPE_CHECKING,
)
if TYPE_CHECKING:
from .core import Connection
class Cursor:
def __init__(self, conn: "Connection", cursor: sqlite3.Cursor) -> None:
self.iter_chunk_size = conn._iter_chunk_size
self._conn = conn
self._cursor = cursor
def __aiter__(self) -> AsyncIterator[sqlite3.Row]:
"""The cursor proxy is also an async iterator."""
return self._fetch_chunked()
async def _fetch_chunked(self):
while True:
rows = await self.fetchmany(self.iter_chunk_size)
if not rows:
return
for row in rows:
yield row
async def _execute(self, fn, *args, **kwargs):
"""Execute the given function on the shared connection's thread."""
return await self._conn._execute(fn, *args, **kwargs)
async def execute(
self, sql: str, parameters: Optional[Iterable[Any]] = None
) -> "Cursor":
"""Execute the given query."""
if parameters is None:
parameters = []
await self._execute(self._cursor.execute, sql, parameters)
return self
async def executemany(
self, sql: str, parameters: Iterable[Iterable[Any]]
) -> "Cursor":
"""Execute the given multiquery."""
await self._execute(self._cursor.executemany, sql, parameters)
return self
async def executescript(self, sql_script: str) -> "Cursor":
"""Execute a user script."""
await self._execute(self._cursor.executescript, sql_script)
return self
async def fetchone(self) -> Optional[sqlite3.Row]:
"""Fetch a single row."""
return await self._execute(self._cursor.fetchone)
async def fetchmany(self, size: Optional[int] = None) -> Iterable[sqlite3.Row]:
"""Fetch up to `cursor.arraysize` number of rows."""
args: Tuple[int, ...] = ()
if size is not None:
args = (size,)
return await self._execute(self._cursor.fetchmany, *args)
async def fetchall(self) -> Iterable[sqlite3.Row]:
"""Fetch all remaining rows."""
return await self._execute(self._cursor.fetchall)
async def close(self) -> None:
"""Close the cursor."""
await self._execute(self._cursor.close)
@property
def rowcount(self) -> int:
return self._cursor.rowcount
@property
def lastrowid(self) -> Optional[int]:
return self._cursor.lastrowid
@property
def arraysize(self) -> int:
return self._cursor.arraysize
@arraysize.setter
def arraysize(self, value: int) -> None:
self._cursor.arraysize = value
@property
def description(self) -> Tuple[Tuple[str, None, None, None, None, None, None], ...]:
return self._cursor.description
@property
def row_factory(self) -> Optional[Callable[[sqlite3.Cursor, sqlite3.Row], object]]:
return self._cursor.row_factory
@row_factory.setter
def row_factory(self, factory: Optional[Type]) -> None:
self._cursor.row_factory = factory
@property
def connection(self) -> sqlite3.Connection:
return self._cursor.connection
async def __aenter__(self):
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
await self.close()

View File

@@ -0,0 +1,4 @@
# Copyright 2022 Amethyst Reese
# Licensed under the MIT license
from .smoke import SmokeTest

View File

@@ -0,0 +1,7 @@
# Copyright 2022 Amethyst Reese
# Licensed under the MIT license
import unittest
if __name__ == "__main__":
unittest.main(module="aiosqlite.tests", verbosity=2)

Some files were not shown because too many files have changed in this diff Show More